drm/i915: Delay queuing hangcheck to wait-request
[cascardo/linux.git] / drivers / gpu / drm / i915 / i915_irq.c
index 1c21220..5614582 100644 (file)
@@ -336,9 +336,8 @@ void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
        __gen6_disable_pm_irq(dev_priv, mask);
 }
 
-void gen6_reset_rps_interrupts(struct drm_device *dev)
+void gen6_reset_rps_interrupts(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        i915_reg_t reg = gen6_pm_iir(dev_priv);
 
        spin_lock_irq(&dev_priv->irq_lock);
@@ -349,10 +348,8 @@ void gen6_reset_rps_interrupts(struct drm_device *dev)
        spin_unlock_irq(&dev_priv->irq_lock);
 }
 
-void gen6_enable_rps_interrupts(struct drm_device *dev)
+void gen6_enable_rps_interrupts(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
        spin_lock_irq(&dev_priv->irq_lock);
 
        WARN_ON(dev_priv->rps.pm_iir);
@@ -367,25 +364,11 @@ void gen6_enable_rps_interrupts(struct drm_device *dev)
 
 u32 gen6_sanitize_rps_pm_mask(struct drm_i915_private *dev_priv, u32 mask)
 {
-       /*
-        * SNB,IVB can while VLV,CHV may hard hang on looping batchbuffer
-        * if GEN6_PM_UP_EI_EXPIRED is masked.
-        *
-        * TODO: verify if this can be reproduced on VLV,CHV.
-        */
-       if (INTEL_INFO(dev_priv)->gen <= 7 && !IS_HASWELL(dev_priv))
-               mask &= ~GEN6_PM_RP_UP_EI_EXPIRED;
-
-       if (INTEL_INFO(dev_priv)->gen >= 8)
-               mask &= ~GEN8_PMINTR_REDIRECT_TO_NON_DISP;
-
-       return mask;
+       return (mask & ~dev_priv->rps.pm_intr_keep);
 }
 
-void gen6_disable_rps_interrupts(struct drm_device *dev)
+void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
        spin_lock_irq(&dev_priv->irq_lock);
        dev_priv->rps.interrupts_enabled = false;
        spin_unlock_irq(&dev_priv->irq_lock);
@@ -402,7 +385,7 @@ void gen6_disable_rps_interrupts(struct drm_device *dev)
 
        spin_unlock_irq(&dev_priv->irq_lock);
 
-       synchronize_irq(dev->irq);
+       synchronize_irq(dev_priv->dev->irq);
 }
 
 /**
@@ -605,19 +588,17 @@ i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
 
 /**
  * i915_enable_asle_pipestat - enable ASLE pipestat for OpRegion
- * @dev: drm device
+ * @dev_priv: i915 device private
  */
-static void i915_enable_asle_pipestat(struct drm_device *dev)
+static void i915_enable_asle_pipestat(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (!dev_priv->opregion.asle || !IS_MOBILE(dev))
+       if (!dev_priv->opregion.asle || !IS_MOBILE(dev_priv))
                return;
 
        spin_lock_irq(&dev_priv->irq_lock);
 
        i915_enable_pipestat(dev_priv, PIPE_B, PIPE_LEGACY_BLC_EVENT_STATUS);
-       if (INTEL_INFO(dev)->gen >= 4)
+       if (INTEL_GEN(dev_priv) >= 4)
                i915_enable_pipestat(dev_priv, PIPE_A,
                                     PIPE_LEGACY_BLC_EVENT_STATUS);
 
@@ -750,7 +731,7 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
        if (mode->flags & DRM_MODE_FLAG_INTERLACE)
                vtotal /= 2;
 
-       if (IS_GEN2(dev))
+       if (IS_GEN2(dev_priv))
                position = I915_READ_FW(PIPEDSL(pipe)) & DSL_LINEMASK_GEN2;
        else
                position = I915_READ_FW(PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
@@ -767,7 +748,7 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
         * problem.  We may need to extend this to include other platforms,
         * but so far testing only shows the problem on HSW.
         */
-       if (HAS_DDI(dev) && !position) {
+       if (HAS_DDI(dev_priv) && !position) {
                int i, temp;
 
                for (i = 0; i < 100; i++) {
@@ -835,7 +816,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
        if (stime)
                *stime = ktime_get();
 
-       if (IS_GEN2(dev) || IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
+       if (IS_GEN2(dev_priv) || IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5) {
                /* No obvious pixelcount register. Only query vertical
                 * scanout position from Display scan line register.
                 */
@@ -897,7 +878,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
        else
                position += vtotal - vbl_end;
 
-       if (IS_GEN2(dev) || IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
+       if (IS_GEN2(dev_priv) || IS_G4X(dev_priv) || INTEL_GEN(dev_priv) >= 5) {
                *vpos = position;
                *hpos = 0;
        } else {
@@ -955,9 +936,8 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe,
                                                     &crtc->hwmode);
 }
 
-static void ironlake_rps_change_irq_handler(struct drm_device *dev)
+static void ironlake_rps_change_irq_handler(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 busy_up, busy_down, max_avg, min_avg;
        u8 new_delay;
 
@@ -986,7 +966,7 @@ static void ironlake_rps_change_irq_handler(struct drm_device *dev)
                        new_delay = dev_priv->ips.min_delay;
        }
 
-       if (ironlake_set_drps(dev, new_delay))
+       if (ironlake_set_drps(dev_priv, new_delay))
                dev_priv->ips.cur_delay = new_delay;
 
        spin_unlock(&mchdev_lock);
@@ -994,14 +974,15 @@ static void ironlake_rps_change_irq_handler(struct drm_device *dev)
        return;
 }
 
-static void notify_ring(struct intel_engine_cs *ring)
+static void notify_ring(struct intel_engine_cs *engine)
 {
-       if (!intel_ring_initialized(ring))
+       if (!intel_engine_initialized(engine))
                return;
 
-       trace_i915_gem_request_notify(ring);
+       trace_i915_gem_request_notify(engine);
+       engine->user_interrupts++;
 
-       wake_up_all(&ring->irq_queue);
+       wake_up_all(&engine->irq_queue);
 }
 
 static void vlv_c0_read(struct drm_i915_private *dev_priv,
@@ -1079,11 +1060,10 @@ static u32 vlv_wa_c0_ei(struct drm_i915_private *dev_priv, u32 pm_iir)
 
 static bool any_waiters(struct drm_i915_private *dev_priv)
 {
-       struct intel_engine_cs *ring;
-       int i;
+       struct intel_engine_cs *engine;
 
-       for_each_ring(ring, dev_priv, i)
-               if (ring->irq_refcount)
+       for_each_engine(engine, dev_priv)
+               if (engine->irq_refcount)
                        return true;
 
        return false;
@@ -1175,7 +1155,7 @@ static void gen6_pm_rps_work(struct work_struct *work)
        new_delay += adj;
        new_delay = clamp_t(int, new_delay, min, max);
 
-       intel_set_rps(dev_priv->dev, new_delay);
+       intel_set_rps(dev_priv, new_delay);
 
        mutex_unlock(&dev_priv->rps.hw_lock);
 out:
@@ -1219,7 +1199,7 @@ static void ivybridge_parity_work(struct work_struct *work)
                i915_reg_t reg;
 
                slice--;
-               if (WARN_ON_ONCE(slice >= NUM_L3_SLICES(dev_priv->dev)))
+               if (WARN_ON_ONCE(slice >= NUM_L3_SLICES(dev_priv)))
                        break;
 
                dev_priv->l3_parity.which_slice &= ~(1<<slice);
@@ -1258,24 +1238,23 @@ static void ivybridge_parity_work(struct work_struct *work)
 out:
        WARN_ON(dev_priv->l3_parity.which_slice);
        spin_lock_irq(&dev_priv->irq_lock);
-       gen5_enable_gt_irq(dev_priv, GT_PARITY_ERROR(dev_priv->dev));
+       gen5_enable_gt_irq(dev_priv, GT_PARITY_ERROR(dev_priv));
        spin_unlock_irq(&dev_priv->irq_lock);
 
        mutex_unlock(&dev_priv->dev->struct_mutex);
 }
 
-static void ivybridge_parity_error_irq_handler(struct drm_device *dev, u32 iir)
+static void ivybridge_parity_error_irq_handler(struct drm_i915_private *dev_priv,
+                                              u32 iir)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (!HAS_L3_DPF(dev))
+       if (!HAS_L3_DPF(dev_priv))
                return;
 
        spin_lock(&dev_priv->irq_lock);
-       gen5_disable_gt_irq(dev_priv, GT_PARITY_ERROR(dev));
+       gen5_disable_gt_irq(dev_priv, GT_PARITY_ERROR(dev_priv));
        spin_unlock(&dev_priv->irq_lock);
 
-       iir &= GT_PARITY_ERROR(dev);
+       iir &= GT_PARITY_ERROR(dev_priv);
        if (iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT_S1)
                dev_priv->l3_parity.which_slice |= 1 << 1;
 
@@ -1285,102 +1264,85 @@ static void ivybridge_parity_error_irq_handler(struct drm_device *dev, u32 iir)
        queue_work(dev_priv->wq, &dev_priv->l3_parity.error_work);
 }
 
-static void ilk_gt_irq_handler(struct drm_device *dev,
-                              struct drm_i915_private *dev_priv,
+static void ilk_gt_irq_handler(struct drm_i915_private *dev_priv,
                               u32 gt_iir)
 {
        if (gt_iir &
            (GT_RENDER_USER_INTERRUPT | GT_RENDER_PIPECTL_NOTIFY_INTERRUPT))
-               notify_ring(&dev_priv->ring[RCS]);
+               notify_ring(&dev_priv->engine[RCS]);
        if (gt_iir & ILK_BSD_USER_INTERRUPT)
-               notify_ring(&dev_priv->ring[VCS]);
+               notify_ring(&dev_priv->engine[VCS]);
 }
 
-static void snb_gt_irq_handler(struct drm_device *dev,
-                              struct drm_i915_private *dev_priv,
+static void snb_gt_irq_handler(struct drm_i915_private *dev_priv,
                               u32 gt_iir)
 {
 
        if (gt_iir &
            (GT_RENDER_USER_INTERRUPT | GT_RENDER_PIPECTL_NOTIFY_INTERRUPT))
-               notify_ring(&dev_priv->ring[RCS]);
+               notify_ring(&dev_priv->engine[RCS]);
        if (gt_iir & GT_BSD_USER_INTERRUPT)
-               notify_ring(&dev_priv->ring[VCS]);
+               notify_ring(&dev_priv->engine[VCS]);
        if (gt_iir & GT_BLT_USER_INTERRUPT)
-               notify_ring(&dev_priv->ring[BCS]);
+               notify_ring(&dev_priv->engine[BCS]);
 
        if (gt_iir & (GT_BLT_CS_ERROR_INTERRUPT |
                      GT_BSD_CS_ERROR_INTERRUPT |
                      GT_RENDER_CS_MASTER_ERROR_INTERRUPT))
                DRM_DEBUG("Command parser error, gt_iir 0x%08x\n", gt_iir);
 
-       if (gt_iir & GT_PARITY_ERROR(dev))
-               ivybridge_parity_error_irq_handler(dev, gt_iir);
+       if (gt_iir & GT_PARITY_ERROR(dev_priv))
+               ivybridge_parity_error_irq_handler(dev_priv, gt_iir);
 }
 
 static __always_inline void
-gen8_cs_irq_handler(struct intel_engine_cs *ring, u32 iir, int test_shift)
+gen8_cs_irq_handler(struct intel_engine_cs *engine, u32 iir, int test_shift)
 {
        if (iir & (GT_RENDER_USER_INTERRUPT << test_shift))
-               notify_ring(ring);
+               notify_ring(engine);
        if (iir & (GT_CONTEXT_SWITCH_INTERRUPT << test_shift))
-               intel_lrc_irq_handler(ring);
+               tasklet_schedule(&engine->irq_tasklet);
 }
 
-static irqreturn_t gen8_gt_irq_handler(struct drm_i915_private *dev_priv,
-                                      u32 master_ctl)
+static irqreturn_t gen8_gt_irq_ack(struct drm_i915_private *dev_priv,
+                                  u32 master_ctl,
+                                  u32 gt_iir[4])
 {
        irqreturn_t ret = IRQ_NONE;
 
        if (master_ctl & (GEN8_GT_RCS_IRQ | GEN8_GT_BCS_IRQ)) {
-               u32 iir = I915_READ_FW(GEN8_GT_IIR(0));
-               if (iir) {
-                       I915_WRITE_FW(GEN8_GT_IIR(0), iir);
+               gt_iir[0] = I915_READ_FW(GEN8_GT_IIR(0));
+               if (gt_iir[0]) {
+                       I915_WRITE_FW(GEN8_GT_IIR(0), gt_iir[0]);
                        ret = IRQ_HANDLED;
-
-                       gen8_cs_irq_handler(&dev_priv->ring[RCS],
-                                       iir, GEN8_RCS_IRQ_SHIFT);
-
-                       gen8_cs_irq_handler(&dev_priv->ring[BCS],
-                                       iir, GEN8_BCS_IRQ_SHIFT);
                } else
                        DRM_ERROR("The master control interrupt lied (GT0)!\n");
        }
 
        if (master_ctl & (GEN8_GT_VCS1_IRQ | GEN8_GT_VCS2_IRQ)) {
-               u32 iir = I915_READ_FW(GEN8_GT_IIR(1));
-               if (iir) {
-                       I915_WRITE_FW(GEN8_GT_IIR(1), iir);
+               gt_iir[1] = I915_READ_FW(GEN8_GT_IIR(1));
+               if (gt_iir[1]) {
+                       I915_WRITE_FW(GEN8_GT_IIR(1), gt_iir[1]);
                        ret = IRQ_HANDLED;
-
-                       gen8_cs_irq_handler(&dev_priv->ring[VCS],
-                                       iir, GEN8_VCS1_IRQ_SHIFT);
-
-                       gen8_cs_irq_handler(&dev_priv->ring[VCS2],
-                                       iir, GEN8_VCS2_IRQ_SHIFT);
                } else
                        DRM_ERROR("The master control interrupt lied (GT1)!\n");
        }
 
        if (master_ctl & GEN8_GT_VECS_IRQ) {
-               u32 iir = I915_READ_FW(GEN8_GT_IIR(3));
-               if (iir) {
-                       I915_WRITE_FW(GEN8_GT_IIR(3), iir);
+               gt_iir[3] = I915_READ_FW(GEN8_GT_IIR(3));
+               if (gt_iir[3]) {
+                       I915_WRITE_FW(GEN8_GT_IIR(3), gt_iir[3]);
                        ret = IRQ_HANDLED;
-
-                       gen8_cs_irq_handler(&dev_priv->ring[VECS],
-                                       iir, GEN8_VECS_IRQ_SHIFT);
                } else
                        DRM_ERROR("The master control interrupt lied (GT3)!\n");
        }
 
        if (master_ctl & GEN8_GT_PM_IRQ) {
-               u32 iir = I915_READ_FW(GEN8_GT_IIR(2));
-               if (iir & dev_priv->pm_rps_events) {
+               gt_iir[2] = I915_READ_FW(GEN8_GT_IIR(2));
+               if (gt_iir[2] & dev_priv->pm_rps_events) {
                        I915_WRITE_FW(GEN8_GT_IIR(2),
-                                     iir & dev_priv->pm_rps_events);
+                                     gt_iir[2] & dev_priv->pm_rps_events);
                        ret = IRQ_HANDLED;
-                       gen6_rps_irq_handler(dev_priv, iir);
                } else
                        DRM_ERROR("The master control interrupt lied (PM)!\n");
        }
@@ -1388,6 +1350,31 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_i915_private *dev_priv,
        return ret;
 }
 
+static void gen8_gt_irq_handler(struct drm_i915_private *dev_priv,
+                               u32 gt_iir[4])
+{
+       if (gt_iir[0]) {
+               gen8_cs_irq_handler(&dev_priv->engine[RCS],
+                                   gt_iir[0], GEN8_RCS_IRQ_SHIFT);
+               gen8_cs_irq_handler(&dev_priv->engine[BCS],
+                                   gt_iir[0], GEN8_BCS_IRQ_SHIFT);
+       }
+
+       if (gt_iir[1]) {
+               gen8_cs_irq_handler(&dev_priv->engine[VCS],
+                                   gt_iir[1], GEN8_VCS1_IRQ_SHIFT);
+               gen8_cs_irq_handler(&dev_priv->engine[VCS2],
+                                   gt_iir[1], GEN8_VCS2_IRQ_SHIFT);
+       }
+
+       if (gt_iir[3])
+               gen8_cs_irq_handler(&dev_priv->engine[VECS],
+                                   gt_iir[3], GEN8_VECS_IRQ_SHIFT);
+
+       if (gt_iir[2] & dev_priv->pm_rps_events)
+               gen6_rps_irq_handler(dev_priv, gt_iir[2]);
+}
+
 static bool bxt_port_hotplug_long_detect(enum port port, u32 val)
 {
        switch (port) {
@@ -1499,27 +1486,23 @@ static void intel_get_hpd_pins(u32 *pin_mask, u32 *long_mask,
 
 }
 
-static void gmbus_irq_handler(struct drm_device *dev)
+static void gmbus_irq_handler(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
        wake_up_all(&dev_priv->gmbus_wait_queue);
 }
 
-static void dp_aux_irq_handler(struct drm_device *dev)
+static void dp_aux_irq_handler(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
        wake_up_all(&dev_priv->gmbus_wait_queue);
 }
 
 #if defined(CONFIG_DEBUG_FS)
-static void display_pipe_crc_irq_handler(struct drm_device *dev, enum pipe pipe,
+static void display_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
+                                        enum pipe pipe,
                                         uint32_t crc0, uint32_t crc1,
                                         uint32_t crc2, uint32_t crc3,
                                         uint32_t crc4)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe];
        struct intel_pipe_crc_entry *entry;
        int head, tail;
@@ -1543,7 +1526,8 @@ static void display_pipe_crc_irq_handler(struct drm_device *dev, enum pipe pipe,
 
        entry = &pipe_crc->entries[head];
 
-       entry->frame = dev->driver->get_vblank_counter(dev, pipe);
+       entry->frame = dev_priv->dev->driver->get_vblank_counter(dev_priv->dev,
+                                                                pipe);
        entry->crc[0] = crc0;
        entry->crc[1] = crc1;
        entry->crc[2] = crc2;
@@ -1559,27 +1543,26 @@ static void display_pipe_crc_irq_handler(struct drm_device *dev, enum pipe pipe,
 }
 #else
 static inline void
-display_pipe_crc_irq_handler(struct drm_device *dev, enum pipe pipe,
+display_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
+                            enum pipe pipe,
                             uint32_t crc0, uint32_t crc1,
                             uint32_t crc2, uint32_t crc3,
                             uint32_t crc4) {}
 #endif
 
 
-static void hsw_pipe_crc_irq_handler(struct drm_device *dev, enum pipe pipe)
+static void hsw_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
+                                    enum pipe pipe)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       display_pipe_crc_irq_handler(dev, pipe,
+       display_pipe_crc_irq_handler(dev_priv, pipe,
                                     I915_READ(PIPE_CRC_RES_1_IVB(pipe)),
                                     0, 0, 0, 0);
 }
 
-static void ivb_pipe_crc_irq_handler(struct drm_device *dev, enum pipe pipe)
+static void ivb_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
+                                    enum pipe pipe)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       display_pipe_crc_irq_handler(dev, pipe,
+       display_pipe_crc_irq_handler(dev_priv, pipe,
                                     I915_READ(PIPE_CRC_RES_1_IVB(pipe)),
                                     I915_READ(PIPE_CRC_RES_2_IVB(pipe)),
                                     I915_READ(PIPE_CRC_RES_3_IVB(pipe)),
@@ -1587,22 +1570,22 @@ static void ivb_pipe_crc_irq_handler(struct drm_device *dev, enum pipe pipe)
                                     I915_READ(PIPE_CRC_RES_5_IVB(pipe)));
 }
 
-static void i9xx_pipe_crc_irq_handler(struct drm_device *dev, enum pipe pipe)
+static void i9xx_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
+                                     enum pipe pipe)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t res1, res2;
 
-       if (INTEL_INFO(dev)->gen >= 3)
+       if (INTEL_GEN(dev_priv) >= 3)
                res1 = I915_READ(PIPE_CRC_RES_RES1_I915(pipe));
        else
                res1 = 0;
 
-       if (INTEL_INFO(dev)->gen >= 5 || IS_G4X(dev))
+       if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
                res2 = I915_READ(PIPE_CRC_RES_RES2_G4X(pipe));
        else
                res2 = 0;
 
-       display_pipe_crc_irq_handler(dev, pipe,
+       display_pipe_crc_irq_handler(dev_priv, pipe,
                                     I915_READ(PIPE_CRC_RES_RED(pipe)),
                                     I915_READ(PIPE_CRC_RES_GREEN(pipe)),
                                     I915_READ(PIPE_CRC_RES_BLUE(pipe)),
@@ -1627,27 +1610,30 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
        if (INTEL_INFO(dev_priv)->gen >= 8)
                return;
 
-       if (HAS_VEBOX(dev_priv->dev)) {
+       if (HAS_VEBOX(dev_priv)) {
                if (pm_iir & PM_VEBOX_USER_INTERRUPT)
-                       notify_ring(&dev_priv->ring[VECS]);
+                       notify_ring(&dev_priv->engine[VECS]);
 
                if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT)
                        DRM_DEBUG("Command parser error, pm_iir 0x%08x\n", pm_iir);
        }
 }
 
-static bool intel_pipe_handle_vblank(struct drm_device *dev, enum pipe pipe)
+static bool intel_pipe_handle_vblank(struct drm_i915_private *dev_priv,
+                                    enum pipe pipe)
 {
-       if (!drm_handle_vblank(dev, pipe))
-               return false;
+       bool ret;
 
-       return true;
+       ret = drm_handle_vblank(dev_priv->dev, pipe);
+       if (ret)
+               intel_finish_page_flip_mmio(dev_priv, pipe);
+
+       return ret;
 }
 
-static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
+static void valleyview_pipestat_irq_ack(struct drm_i915_private *dev_priv,
+                                       u32 iir, u32 pipe_stats[I915_MAX_PIPES])
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 pipe_stats[I915_MAX_PIPES] = { };
        int pipe;
 
        spin_lock(&dev_priv->irq_lock);
@@ -1701,45 +1687,49 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
                        I915_WRITE(reg, pipe_stats[pipe]);
        }
        spin_unlock(&dev_priv->irq_lock);
+}
+
+static void valleyview_pipestat_irq_handler(struct drm_i915_private *dev_priv,
+                                           u32 pipe_stats[I915_MAX_PIPES])
+{
+       enum pipe pipe;
 
        for_each_pipe(dev_priv, pipe) {
                if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS &&
-                   intel_pipe_handle_vblank(dev, pipe))
-                       intel_check_page_flip(dev, pipe);
+                   intel_pipe_handle_vblank(dev_priv, pipe))
+                       intel_check_page_flip(dev_priv, 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] & PLANE_FLIP_DONE_INT_STATUS_VLV)
+                       intel_finish_page_flip_cs(dev_priv, pipe);
 
                if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
-                       i9xx_pipe_crc_irq_handler(dev, pipe);
+                       i9xx_pipe_crc_irq_handler(dev_priv, pipe);
 
                if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
                        intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
        }
 
        if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
-               gmbus_irq_handler(dev);
+               gmbus_irq_handler(dev_priv);
 }
 
-static void i9xx_hpd_irq_handler(struct drm_device *dev)
+static u32 i9xx_hpd_irq_ack(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
-       u32 pin_mask = 0, long_mask = 0;
 
-       if (!hotplug_status)
-               return;
+       if (hotplug_status)
+               I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
 
-       I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
-       /*
-        * Make sure hotplug status is cleared before we clear IIR, or else we
-        * may miss hotplug events.
-        */
-       POSTING_READ(PORT_HOTPLUG_STAT);
+       return hotplug_status;
+}
+
+static void i9xx_hpd_irq_handler(struct drm_i915_private *dev_priv,
+                                u32 hotplug_status)
+{
+       u32 pin_mask = 0, long_mask = 0;
 
-       if (IS_G4X(dev) || IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
+       if (IS_G4X(dev_priv) || IS_VALLEYVIEW(dev_priv) ||
+           IS_CHERRYVIEW(dev_priv)) {
                u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X;
 
                if (hotplug_trigger) {
@@ -1747,11 +1737,11 @@ static void i9xx_hpd_irq_handler(struct drm_device *dev)
                                           hotplug_trigger, hpd_status_g4x,
                                           i9xx_port_hotplug_long_detect);
 
-                       intel_hpd_irq_handler(dev, pin_mask, long_mask);
+                       intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
                }
 
                if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X)
-                       dp_aux_irq_handler(dev);
+                       dp_aux_irq_handler(dev_priv);
        } else {
                u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
 
@@ -1759,7 +1749,7 @@ static void i9xx_hpd_irq_handler(struct drm_device *dev)
                        intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
                                           hotplug_trigger, hpd_status_i915,
                                           i9xx_port_hotplug_long_detect);
-                       intel_hpd_irq_handler(dev, pin_mask, long_mask);
+                       intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
                }
        }
 }
@@ -1768,7 +1758,6 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 {
        struct drm_device *dev = arg;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 iir, gt_iir, pm_iir;
        irqreturn_t ret = IRQ_NONE;
 
        if (!intel_irqs_enabled(dev_priv))
@@ -1777,40 +1766,72 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
        /* IRQs are synced during runtime_suspend, we don't require a wakeref */
        disable_rpm_wakeref_asserts(dev_priv);
 
-       while (true) {
-               /* Find, clear, then process each source of interrupt */
+       do {
+               u32 iir, gt_iir, pm_iir;
+               u32 pipe_stats[I915_MAX_PIPES] = {};
+               u32 hotplug_status = 0;
+               u32 ier = 0;
 
                gt_iir = I915_READ(GTIIR);
-               if (gt_iir)
-                       I915_WRITE(GTIIR, gt_iir);
-
                pm_iir = I915_READ(GEN6_PMIIR);
-               if (pm_iir)
-                       I915_WRITE(GEN6_PMIIR, pm_iir);
-
                iir = I915_READ(VLV_IIR);
-               if (iir) {
-                       /* Consume port before clearing IIR or we'll miss events */
-                       if (iir & I915_DISPLAY_PORT_INTERRUPT)
-                               i9xx_hpd_irq_handler(dev);
-                       I915_WRITE(VLV_IIR, iir);
-               }
 
                if (gt_iir == 0 && pm_iir == 0 && iir == 0)
-                       goto out;
+                       break;
 
                ret = IRQ_HANDLED;
 
+               /*
+                * Theory on interrupt generation, based on empirical evidence:
+                *
+                * x = ((VLV_IIR & VLV_IER) ||
+                *      (((GT_IIR & GT_IER) || (GEN6_PMIIR & GEN6_PMIER)) &&
+                *       (VLV_MASTER_IER & MASTER_INTERRUPT_ENABLE)));
+                *
+                * A CPU interrupt will only be raised when 'x' has a 0->1 edge.
+                * Hence we clear MASTER_INTERRUPT_ENABLE and VLV_IER to
+                * guarantee the CPU interrupt will be raised again even if we
+                * don't end up clearing all the VLV_IIR, GT_IIR, GEN6_PMIIR
+                * bits this time around.
+                */
+               I915_WRITE(VLV_MASTER_IER, 0);
+               ier = I915_READ(VLV_IER);
+               I915_WRITE(VLV_IER, 0);
+
                if (gt_iir)
-                       snb_gt_irq_handler(dev, dev_priv, gt_iir);
+                       I915_WRITE(GTIIR, gt_iir);
                if (pm_iir)
-                       gen6_rps_irq_handler(dev_priv, pm_iir);
+                       I915_WRITE(GEN6_PMIIR, pm_iir);
+
+               if (iir & I915_DISPLAY_PORT_INTERRUPT)
+                       hotplug_status = i9xx_hpd_irq_ack(dev_priv);
+
                /* Call regardless, as some status bits might not be
                 * signalled in iir */
-               valleyview_pipestat_irq_handler(dev, iir);
-       }
+               valleyview_pipestat_irq_ack(dev_priv, iir, pipe_stats);
+
+               /*
+                * VLV_IIR is single buffered, and reflects the level
+                * from PIPESTAT/PORT_HOTPLUG_STAT, hence clear it last.
+                */
+               if (iir)
+                       I915_WRITE(VLV_IIR, iir);
+
+               I915_WRITE(VLV_IER, ier);
+               I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE);
+               POSTING_READ(VLV_MASTER_IER);
+
+               if (gt_iir)
+                       snb_gt_irq_handler(dev_priv, gt_iir);
+               if (pm_iir)
+                       gen6_rps_irq_handler(dev_priv, pm_iir);
+
+               if (hotplug_status)
+                       i9xx_hpd_irq_handler(dev_priv, hotplug_status);
+
+               valleyview_pipestat_irq_handler(dev_priv, pipe_stats);
+       } while (0);
 
-out:
        enable_rpm_wakeref_asserts(dev_priv);
 
        return ret;
@@ -1820,7 +1841,6 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
 {
        struct drm_device *dev = arg;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 master_ctl, iir;
        irqreturn_t ret = IRQ_NONE;
 
        if (!intel_irqs_enabled(dev_priv))
@@ -1830,6 +1850,12 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
        disable_rpm_wakeref_asserts(dev_priv);
 
        do {
+               u32 master_ctl, iir;
+               u32 gt_iir[4] = {};
+               u32 pipe_stats[I915_MAX_PIPES] = {};
+               u32 hotplug_status = 0;
+               u32 ier = 0;
+
                master_ctl = I915_READ(GEN8_MASTER_IRQ) & ~GEN8_MASTER_IRQ_CONTROL;
                iir = I915_READ(VLV_IIR);
 
@@ -1838,25 +1864,49 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
 
                ret = IRQ_HANDLED;
 
+               /*
+                * Theory on interrupt generation, based on empirical evidence:
+                *
+                * x = ((VLV_IIR & VLV_IER) ||
+                *      ((GEN8_MASTER_IRQ & ~GEN8_MASTER_IRQ_CONTROL) &&
+                *       (GEN8_MASTER_IRQ & GEN8_MASTER_IRQ_CONTROL)));
+                *
+                * A CPU interrupt will only be raised when 'x' has a 0->1 edge.
+                * Hence we clear GEN8_MASTER_IRQ_CONTROL and VLV_IER to
+                * guarantee the CPU interrupt will be raised again even if we
+                * don't end up clearing all the VLV_IIR and GEN8_MASTER_IRQ_CONTROL
+                * bits this time around.
+                */
                I915_WRITE(GEN8_MASTER_IRQ, 0);
+               ier = I915_READ(VLV_IER);
+               I915_WRITE(VLV_IER, 0);
 
-               /* Find, clear, then process each source of interrupt */
-
-               if (iir) {
-                       /* Consume port before clearing IIR or we'll miss events */
-                       if (iir & I915_DISPLAY_PORT_INTERRUPT)
-                               i9xx_hpd_irq_handler(dev);
-                       I915_WRITE(VLV_IIR, iir);
-               }
+               gen8_gt_irq_ack(dev_priv, master_ctl, gt_iir);
 
-               gen8_gt_irq_handler(dev_priv, master_ctl);
+               if (iir & I915_DISPLAY_PORT_INTERRUPT)
+                       hotplug_status = i9xx_hpd_irq_ack(dev_priv);
 
                /* Call regardless, as some status bits might not be
                 * signalled in iir */
-               valleyview_pipestat_irq_handler(dev, iir);
+               valleyview_pipestat_irq_ack(dev_priv, iir, pipe_stats);
+
+               /*
+                * VLV_IIR is single buffered, and reflects the level
+                * from PIPESTAT/PORT_HOTPLUG_STAT, hence clear it last.
+                */
+               if (iir)
+                       I915_WRITE(VLV_IIR, iir);
 
-               I915_WRITE(GEN8_MASTER_IRQ, DE_MASTER_IRQ_CONTROL);
+               I915_WRITE(VLV_IER, ier);
+               I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
                POSTING_READ(GEN8_MASTER_IRQ);
+
+               gen8_gt_irq_handler(dev_priv, gt_iir);
+
+               if (hotplug_status)
+                       i9xx_hpd_irq_handler(dev_priv, hotplug_status);
+
+               valleyview_pipestat_irq_handler(dev_priv, pipe_stats);
        } while (0);
 
        enable_rpm_wakeref_asserts(dev_priv);
@@ -1864,10 +1914,10 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
        return ret;
 }
 
-static void ibx_hpd_irq_handler(struct drm_device *dev, u32 hotplug_trigger,
+static void ibx_hpd_irq_handler(struct drm_i915_private *dev_priv,
+                               u32 hotplug_trigger,
                                const u32 hpd[HPD_NUM_PINS])
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0;
 
        /*
@@ -1893,16 +1943,15 @@ static void ibx_hpd_irq_handler(struct drm_device *dev, u32 hotplug_trigger,
                           dig_hotplug_reg, hpd,
                           pch_port_hotplug_long_detect);
 
-       intel_hpd_irq_handler(dev, pin_mask, long_mask);
+       intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
 }
 
-static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
+static void ibx_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe;
        u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK;
 
-       ibx_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx);
+       ibx_hpd_irq_handler(dev_priv, hotplug_trigger, hpd_ibx);
 
        if (pch_iir & SDE_AUDIO_POWER_MASK) {
                int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >>
@@ -1912,10 +1961,10 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
        }
 
        if (pch_iir & SDE_AUX_MASK)
-               dp_aux_irq_handler(dev);
+               dp_aux_irq_handler(dev_priv);
 
        if (pch_iir & SDE_GMBUS)
-               gmbus_irq_handler(dev);
+               gmbus_irq_handler(dev_priv);
 
        if (pch_iir & SDE_AUDIO_HDCP_MASK)
                DRM_DEBUG_DRIVER("PCH HDCP audio interrupt\n");
@@ -1945,9 +1994,8 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
                intel_pch_fifo_underrun_irq_handler(dev_priv, TRANSCODER_B);
 }
 
-static void ivb_err_int_handler(struct drm_device *dev)
+static void ivb_err_int_handler(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 err_int = I915_READ(GEN7_ERR_INT);
        enum pipe pipe;
 
@@ -1959,19 +2007,18 @@ static void ivb_err_int_handler(struct drm_device *dev)
                        intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
 
                if (err_int & ERR_INT_PIPE_CRC_DONE(pipe)) {
-                       if (IS_IVYBRIDGE(dev))
-                               ivb_pipe_crc_irq_handler(dev, pipe);
+                       if (IS_IVYBRIDGE(dev_priv))
+                               ivb_pipe_crc_irq_handler(dev_priv, pipe);
                        else
-                               hsw_pipe_crc_irq_handler(dev, pipe);
+                               hsw_pipe_crc_irq_handler(dev_priv, pipe);
                }
        }
 
        I915_WRITE(GEN7_ERR_INT, err_int);
 }
 
-static void cpt_serr_int_handler(struct drm_device *dev)
+static void cpt_serr_int_handler(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 serr_int = I915_READ(SERR_INT);
 
        if (serr_int & SERR_INT_POISON)
@@ -1989,13 +2036,12 @@ static void cpt_serr_int_handler(struct drm_device *dev)
        I915_WRITE(SERR_INT, serr_int);
 }
 
-static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
+static void cpt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe;
        u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
 
-       ibx_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt);
+       ibx_hpd_irq_handler(dev_priv, hotplug_trigger, hpd_cpt);
 
        if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) {
                int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >>
@@ -2005,10 +2051,10 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
        }
 
        if (pch_iir & SDE_AUX_MASK_CPT)
-               dp_aux_irq_handler(dev);
+               dp_aux_irq_handler(dev_priv);
 
        if (pch_iir & SDE_GMBUS_CPT)
-               gmbus_irq_handler(dev);
+               gmbus_irq_handler(dev_priv);
 
        if (pch_iir & SDE_AUDIO_CP_REQ_CPT)
                DRM_DEBUG_DRIVER("Audio CP request interrupt\n");
@@ -2023,12 +2069,11 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
                                         I915_READ(FDI_RX_IIR(pipe)));
 
        if (pch_iir & SDE_ERROR_CPT)
-               cpt_serr_int_handler(dev);
+               cpt_serr_int_handler(dev_priv);
 }
 
-static void spt_irq_handler(struct drm_device *dev, u32 pch_iir)
+static void spt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_SPT &
                ~SDE_PORTE_HOTPLUG_SPT;
        u32 hotplug2_trigger = pch_iir & SDE_PORTE_HOTPLUG_SPT;
@@ -2057,16 +2102,16 @@ static void spt_irq_handler(struct drm_device *dev, u32 pch_iir)
        }
 
        if (pin_mask)
-               intel_hpd_irq_handler(dev, pin_mask, long_mask);
+               intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
 
        if (pch_iir & SDE_GMBUS_CPT)
-               gmbus_irq_handler(dev);
+               gmbus_irq_handler(dev_priv);
 }
 
-static void ilk_hpd_irq_handler(struct drm_device *dev, u32 hotplug_trigger,
+static void ilk_hpd_irq_handler(struct drm_i915_private *dev_priv,
+                               u32 hotplug_trigger,
                                const u32 hpd[HPD_NUM_PINS])
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0;
 
        dig_hotplug_reg = I915_READ(DIGITAL_PORT_HOTPLUG_CNTRL);
@@ -2076,97 +2121,93 @@ static void ilk_hpd_irq_handler(struct drm_device *dev, u32 hotplug_trigger,
                           dig_hotplug_reg, hpd,
                           ilk_port_hotplug_long_detect);
 
-       intel_hpd_irq_handler(dev, pin_mask, long_mask);
+       intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
 }
 
-static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
+static void ilk_display_irq_handler(struct drm_i915_private *dev_priv,
+                                   u32 de_iir)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        enum pipe pipe;
        u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG;
 
        if (hotplug_trigger)
-               ilk_hpd_irq_handler(dev, hotplug_trigger, hpd_ilk);
+               ilk_hpd_irq_handler(dev_priv, hotplug_trigger, hpd_ilk);
 
        if (de_iir & DE_AUX_CHANNEL_A)
-               dp_aux_irq_handler(dev);
+               dp_aux_irq_handler(dev_priv);
 
        if (de_iir & DE_GSE)
-               intel_opregion_asle_intr(dev);
+               intel_opregion_asle_intr(dev_priv);
 
        if (de_iir & DE_POISON)
                DRM_ERROR("Poison interrupt\n");
 
        for_each_pipe(dev_priv, pipe) {
                if (de_iir & DE_PIPE_VBLANK(pipe) &&
-                   intel_pipe_handle_vblank(dev, pipe))
-                       intel_check_page_flip(dev, pipe);
+                   intel_pipe_handle_vblank(dev_priv, pipe))
+                       intel_check_page_flip(dev_priv, pipe);
 
                if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe))
                        intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
 
                if (de_iir & DE_PIPE_CRC_DONE(pipe))
-                       i9xx_pipe_crc_irq_handler(dev, pipe);
+                       i9xx_pipe_crc_irq_handler(dev_priv, pipe);
 
                /* plane/pipes map 1:1 on ilk+ */
-               if (de_iir & DE_PLANE_FLIP_DONE(pipe)) {
-                       intel_prepare_page_flip(dev, pipe);
-                       intel_finish_page_flip_plane(dev, pipe);
-               }
+               if (de_iir & DE_PLANE_FLIP_DONE(pipe))
+                       intel_finish_page_flip_cs(dev_priv, pipe);
        }
 
        /* check event from PCH */
        if (de_iir & DE_PCH_EVENT) {
                u32 pch_iir = I915_READ(SDEIIR);
 
-               if (HAS_PCH_CPT(dev))
-                       cpt_irq_handler(dev, pch_iir);
+               if (HAS_PCH_CPT(dev_priv))
+                       cpt_irq_handler(dev_priv, pch_iir);
                else
-                       ibx_irq_handler(dev, pch_iir);
+                       ibx_irq_handler(dev_priv, pch_iir);
 
                /* should clear PCH hotplug event before clear CPU irq */
                I915_WRITE(SDEIIR, pch_iir);
        }
 
-       if (IS_GEN5(dev) && de_iir & DE_PCU_EVENT)
-               ironlake_rps_change_irq_handler(dev);
+       if (IS_GEN5(dev_priv) && de_iir & DE_PCU_EVENT)
+               ironlake_rps_change_irq_handler(dev_priv);
 }
 
-static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
+static void ivb_display_irq_handler(struct drm_i915_private *dev_priv,
+                                   u32 de_iir)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        enum pipe pipe;
        u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG_IVB;
 
        if (hotplug_trigger)
-               ilk_hpd_irq_handler(dev, hotplug_trigger, hpd_ivb);
+               ilk_hpd_irq_handler(dev_priv, hotplug_trigger, hpd_ivb);
 
        if (de_iir & DE_ERR_INT_IVB)
-               ivb_err_int_handler(dev);
+               ivb_err_int_handler(dev_priv);
 
        if (de_iir & DE_AUX_CHANNEL_A_IVB)
-               dp_aux_irq_handler(dev);
+               dp_aux_irq_handler(dev_priv);
 
        if (de_iir & DE_GSE_IVB)
-               intel_opregion_asle_intr(dev);
+               intel_opregion_asle_intr(dev_priv);
 
        for_each_pipe(dev_priv, pipe) {
                if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)) &&
-                   intel_pipe_handle_vblank(dev, pipe))
-                       intel_check_page_flip(dev, pipe);
+                   intel_pipe_handle_vblank(dev_priv, pipe))
+                       intel_check_page_flip(dev_priv, pipe);
 
                /* plane/pipes map 1:1 on ilk+ */
-               if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) {
-                       intel_prepare_page_flip(dev, pipe);
-                       intel_finish_page_flip_plane(dev, pipe);
-               }
+               if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe))
+                       intel_finish_page_flip_cs(dev_priv, pipe);
        }
 
        /* check event from PCH */
-       if (!HAS_PCH_NOP(dev) && (de_iir & DE_PCH_EVENT_IVB)) {
+       if (!HAS_PCH_NOP(dev_priv) && (de_iir & DE_PCH_EVENT_IVB)) {
                u32 pch_iir = I915_READ(SDEIIR);
 
-               cpt_irq_handler(dev, pch_iir);
+               cpt_irq_handler(dev_priv, pch_iir);
 
                /* clear PCH hotplug event before clear CPU irq */
                I915_WRITE(SDEIIR, pch_iir);
@@ -2204,7 +2245,7 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
         * able to process them after we restore SDEIER (as soon as we restore
         * it, we'll get an interrupt if SDEIIR still has something to process
         * due to its back queue). */
-       if (!HAS_PCH_NOP(dev)) {
+       if (!HAS_PCH_NOP(dev_priv)) {
                sde_ier = I915_READ(SDEIER);
                I915_WRITE(SDEIER, 0);
                POSTING_READ(SDEIER);
@@ -2216,23 +2257,23 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
        if (gt_iir) {
                I915_WRITE(GTIIR, gt_iir);
                ret = IRQ_HANDLED;
-               if (INTEL_INFO(dev)->gen >= 6)
-                       snb_gt_irq_handler(dev, dev_priv, gt_iir);
+               if (INTEL_GEN(dev_priv) >= 6)
+                       snb_gt_irq_handler(dev_priv, gt_iir);
                else
-                       ilk_gt_irq_handler(dev, dev_priv, gt_iir);
+                       ilk_gt_irq_handler(dev_priv, gt_iir);
        }
 
        de_iir = I915_READ(DEIIR);
        if (de_iir) {
                I915_WRITE(DEIIR, de_iir);
                ret = IRQ_HANDLED;
-               if (INTEL_INFO(dev)->gen >= 7)
-                       ivb_display_irq_handler(dev, de_iir);
+               if (INTEL_GEN(dev_priv) >= 7)
+                       ivb_display_irq_handler(dev_priv, de_iir);
                else
-                       ilk_display_irq_handler(dev, de_iir);
+                       ilk_display_irq_handler(dev_priv, de_iir);
        }
 
-       if (INTEL_INFO(dev)->gen >= 6) {
+       if (INTEL_GEN(dev_priv) >= 6) {
                u32 pm_iir = I915_READ(GEN6_PMIIR);
                if (pm_iir) {
                        I915_WRITE(GEN6_PMIIR, pm_iir);
@@ -2243,7 +2284,7 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
 
        I915_WRITE(DEIER, de_ier);
        POSTING_READ(DEIER);
-       if (!HAS_PCH_NOP(dev)) {
+       if (!HAS_PCH_NOP(dev_priv)) {
                I915_WRITE(SDEIER, sde_ier);
                POSTING_READ(SDEIER);
        }
@@ -2254,10 +2295,10 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
        return ret;
 }
 
-static void bxt_hpd_irq_handler(struct drm_device *dev, u32 hotplug_trigger,
+static void bxt_hpd_irq_handler(struct drm_i915_private *dev_priv,
+                               u32 hotplug_trigger,
                                const u32 hpd[HPD_NUM_PINS])
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0;
 
        dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG);
@@ -2267,13 +2308,12 @@ static void bxt_hpd_irq_handler(struct drm_device *dev, u32 hotplug_trigger,
                           dig_hotplug_reg, hpd,
                           bxt_port_hotplug_long_detect);
 
-       intel_hpd_irq_handler(dev, pin_mask, long_mask);
+       intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
 }
 
 static irqreturn_t
 gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
 {
-       struct drm_device *dev = dev_priv->dev;
        irqreturn_t ret = IRQ_NONE;
        u32 iir;
        enum pipe pipe;
@@ -2284,7 +2324,7 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
                        I915_WRITE(GEN8_DE_MISC_IIR, iir);
                        ret = IRQ_HANDLED;
                        if (iir & GEN8_DE_MISC_GSE)
-                               intel_opregion_asle_intr(dev);
+                               intel_opregion_asle_intr(dev_priv);
                        else
                                DRM_ERROR("Unexpected DE Misc interrupt\n");
                }
@@ -2308,26 +2348,28 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
                                            GEN9_AUX_CHANNEL_D;
 
                        if (iir & tmp_mask) {
-                               dp_aux_irq_handler(dev);
+                               dp_aux_irq_handler(dev_priv);
                                found = true;
                        }
 
                        if (IS_BROXTON(dev_priv)) {
                                tmp_mask = iir & BXT_DE_PORT_HOTPLUG_MASK;
                                if (tmp_mask) {
-                                       bxt_hpd_irq_handler(dev, tmp_mask, hpd_bxt);
+                                       bxt_hpd_irq_handler(dev_priv, tmp_mask,
+                                                           hpd_bxt);
                                        found = true;
                                }
                        } else if (IS_BROADWELL(dev_priv)) {
                                tmp_mask = iir & GEN8_PORT_DP_A_HOTPLUG;
                                if (tmp_mask) {
-                                       ilk_hpd_irq_handler(dev, tmp_mask, hpd_bdw);
+                                       ilk_hpd_irq_handler(dev_priv,
+                                                           tmp_mask, hpd_bdw);
                                        found = true;
                                }
                        }
 
-                       if (IS_BROXTON(dev) && (iir & BXT_DE_PORT_GMBUS)) {
-                               gmbus_irq_handler(dev);
+                       if (IS_BROXTON(dev_priv) && (iir & BXT_DE_PORT_GMBUS)) {
+                               gmbus_irq_handler(dev_priv);
                                found = true;
                        }
 
@@ -2354,8 +2396,8 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
                I915_WRITE(GEN8_DE_PIPE_IIR(pipe), iir);
 
                if (iir & GEN8_PIPE_VBLANK &&
-                   intel_pipe_handle_vblank(dev, pipe))
-                       intel_check_page_flip(dev, pipe);
+                   intel_pipe_handle_vblank(dev_priv, pipe))
+                       intel_check_page_flip(dev_priv, pipe);
 
                flip_done = iir;
                if (INTEL_INFO(dev_priv)->gen >= 9)
@@ -2363,13 +2405,11 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
                else
                        flip_done &= GEN8_PIPE_PRIMARY_FLIP_DONE;
 
-               if (flip_done) {
-                       intel_prepare_page_flip(dev, pipe);
-                       intel_finish_page_flip_plane(dev, pipe);
-               }
+               if (flip_done)
+                       intel_finish_page_flip_cs(dev_priv, pipe);
 
                if (iir & GEN8_PIPE_CDCLK_CRC_DONE)
-                       hsw_pipe_crc_irq_handler(dev, pipe);
+                       hsw_pipe_crc_irq_handler(dev_priv, pipe);
 
                if (iir & GEN8_PIPE_FIFO_UNDERRUN)
                        intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
@@ -2386,7 +2426,7 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
                                  fault_errors);
        }
 
-       if (HAS_PCH_SPLIT(dev) && !HAS_PCH_NOP(dev) &&
+       if (HAS_PCH_SPLIT(dev_priv) && !HAS_PCH_NOP(dev_priv) &&
            master_ctl & GEN8_DE_PCH_IRQ) {
                /*
                 * FIXME(BDW): Assume for now that the new interrupt handling
@@ -2399,9 +2439,9 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
                        ret = IRQ_HANDLED;
 
                        if (HAS_PCH_SPT(dev_priv))
-                               spt_irq_handler(dev, iir);
+                               spt_irq_handler(dev_priv, iir);
                        else
-                               cpt_irq_handler(dev, iir);
+                               cpt_irq_handler(dev_priv, iir);
                } else {
                        /*
                         * Like on previous PCH there seems to be something
@@ -2419,6 +2459,7 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
        struct drm_device *dev = arg;
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 master_ctl;
+       u32 gt_iir[4] = {};
        irqreturn_t ret;
 
        if (!intel_irqs_enabled(dev_priv))
@@ -2435,7 +2476,8 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
        disable_rpm_wakeref_asserts(dev_priv);
 
        /* Find, clear, then process each source of interrupt */
-       ret = gen8_gt_irq_handler(dev_priv, master_ctl);
+       ret = gen8_gt_irq_ack(dev_priv, master_ctl, gt_iir);
+       gen8_gt_irq_handler(dev_priv, gt_iir);
        ret |= gen8_de_irq_handler(dev_priv, master_ctl);
 
        I915_WRITE_FW(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
@@ -2449,8 +2491,7 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
 static void i915_error_wake_up(struct drm_i915_private *dev_priv,
                               bool reset_completed)
 {
-       struct intel_engine_cs *ring;
-       int i;
+       struct intel_engine_cs *engine;
 
        /*
         * Notify all waiters for GPU completion events that reset state has
@@ -2460,8 +2501,8 @@ static void i915_error_wake_up(struct drm_i915_private *dev_priv,
         */
 
        /* Wake up __wait_seqno, potentially holding dev->struct_mutex. */
-       for_each_ring(ring, dev_priv, i)
-               wake_up_all(&ring->irq_queue);
+       for_each_engine(engine, dev_priv)
+               wake_up_all(&engine->irq_queue);
 
        /* Wake up intel_crtc_wait_for_pending_flips, holding crtc->mutex. */
        wake_up_all(&dev_priv->pending_flip_queue);
@@ -2476,21 +2517,20 @@ static void i915_error_wake_up(struct drm_i915_private *dev_priv,
 
 /**
  * i915_reset_and_wakeup - do process context error handling work
- * @dev: drm device
+ * @dev_priv: i915 device private
  *
  * Fire an error uevent so userspace can see that a hang or error
  * was detected.
  */
-static void i915_reset_and_wakeup(struct drm_device *dev)
+static void i915_reset_and_wakeup(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct i915_gpu_error *error = &dev_priv->gpu_error;
+       struct kobject *kobj = &dev_priv->dev->primary->kdev->kobj;
        char *error_event[] = { I915_ERROR_UEVENT "=1", NULL };
        char *reset_event[] = { I915_RESET_UEVENT "=1", NULL };
        char *reset_done_event[] = { I915_ERROR_UEVENT "=0", NULL };
        int ret;
 
-       kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, error_event);
+       kobject_uevent_env(kobj, KOBJ_CHANGE, error_event);
 
        /*
         * Note that there's only one work item which does gpu resets, so we
@@ -2502,10 +2542,9 @@ static void i915_reset_and_wakeup(struct drm_device *dev)
         * the reset in-progress bit is only ever set by code outside of this
         * work we don't need to worry about any other races.
         */
-       if (i915_reset_in_progress(error) && !i915_terminally_wedged(error)) {
+       if (i915_reset_in_progress(&dev_priv->gpu_error)) {
                DRM_DEBUG_DRIVER("resetting chip\n");
-               kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE,
-                                  reset_event);
+               kobject_uevent_env(kobj, KOBJ_CHANGE, reset_event);
 
                /*
                 * In most cases it's guaranteed that we get here with an RPM
@@ -2516,7 +2555,7 @@ static void i915_reset_and_wakeup(struct drm_device *dev)
                 */
                intel_runtime_pm_get(dev_priv);
 
-               intel_prepare_reset(dev);
+               intel_prepare_reset(dev_priv);
 
                /*
                 * All state reset _must_ be completed before we update the
@@ -2524,31 +2563,15 @@ static void i915_reset_and_wakeup(struct drm_device *dev)
                 * pending state and not properly drop locks, resulting in
                 * deadlocks with the reset work.
                 */
-               ret = i915_reset(dev);
+               ret = i915_reset(dev_priv);
 
-               intel_finish_reset(dev);
+               intel_finish_reset(dev_priv);
 
                intel_runtime_pm_put(dev_priv);
 
-               if (ret == 0) {
-                       /*
-                        * After all the gem state is reset, increment the reset
-                        * counter and wake up everyone waiting for the reset to
-                        * complete.
-                        *
-                        * Since unlock operations are a one-sided barrier only,
-                        * we need to insert a barrier here to order any seqno
-                        * updates before
-                        * the counter increment.
-                        */
-                       smp_mb__before_atomic();
-                       atomic_inc(&dev_priv->gpu_error.reset_counter);
-
-                       kobject_uevent_env(&dev->primary->kdev->kobj,
+               if (ret == 0)
+                       kobject_uevent_env(kobj,
                                           KOBJ_CHANGE, reset_done_event);
-               } else {
-                       atomic_or(I915_WEDGED, &error->reset_counter);
-               }
 
                /*
                 * Note: The wake_up also serves as a memory barrier so that
@@ -2558,9 +2581,8 @@ static void i915_reset_and_wakeup(struct drm_device *dev)
        }
 }
 
-static void i915_report_and_clear_eir(struct drm_device *dev)
+static void i915_report_and_clear_eir(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t instdone[I915_NUM_INSTDONE_REG];
        u32 eir = I915_READ(EIR);
        int pipe, i;
@@ -2570,9 +2592,9 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
 
        pr_err("render error detected, EIR: 0x%08x\n", eir);
 
-       i915_get_extra_instdone(dev, instdone);
+       i915_get_extra_instdone(dev_priv, instdone);
 
-       if (IS_G4X(dev)) {
+       if (IS_G4X(dev_priv)) {
                if (eir & (GM45_ERROR_MEM_PRIV | GM45_ERROR_CP_PRIV)) {
                        u32 ipeir = I915_READ(IPEIR_I965);
 
@@ -2594,7 +2616,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
                }
        }
 
-       if (!IS_GEN2(dev)) {
+       if (!IS_GEN2(dev_priv)) {
                if (eir & I915_ERROR_PAGE_TABLE) {
                        u32 pgtbl_err = I915_READ(PGTBL_ER);
                        pr_err("page table error\n");
@@ -2616,7 +2638,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
                pr_err("  INSTPM: 0x%08x\n", I915_READ(INSTPM));
                for (i = 0; i < ARRAY_SIZE(instdone); i++)
                        pr_err("  INSTDONE_%d: 0x%08x\n", i, instdone[i]);
-               if (INTEL_INFO(dev)->gen < 4) {
+               if (INTEL_GEN(dev_priv) < 4) {
                        u32 ipeir = I915_READ(IPEIR);
 
                        pr_err("  IPEIR: 0x%08x\n", I915_READ(IPEIR));
@@ -2652,18 +2674,19 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
 
 /**
  * i915_handle_error - handle a gpu error
- * @dev: drm device
- *
+ * @dev_priv: i915 device private
+ * @engine_mask: mask representing engines that are hung
  * Do some basic checking of register state at error time and
  * dump it to the syslog.  Also call i915_capture_error_state() to make
  * sure we get a record and make it available in debugfs.  Fire a uevent
  * so userspace knows something bad happened (should trigger collection
  * of a ring dump etc.).
+ * @fmt: Error message format string
  */
-void i915_handle_error(struct drm_device *dev, bool wedged,
+void i915_handle_error(struct drm_i915_private *dev_priv,
+                      u32 engine_mask,
                       const char *fmt, ...)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        va_list args;
        char error_msg[80];
 
@@ -2671,10 +2694,10 @@ void i915_handle_error(struct drm_device *dev, bool wedged,
        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);
+       i915_capture_error_state(dev_priv, engine_mask, error_msg);
+       i915_report_and_clear_eir(dev_priv);
 
-       if (wedged) {
+       if (engine_mask) {
                atomic_or(I915_RESET_IN_PROGRESS_FLAG,
                                &dev_priv->gpu_error.reset_counter);
 
@@ -2694,7 +2717,7 @@ void i915_handle_error(struct drm_device *dev, bool wedged,
                i915_error_wake_up(dev_priv, false);
        }
 
-       i915_reset_and_wakeup(dev);
+       i915_reset_and_wakeup(dev_priv);
 }
 
 /* Called from drm generic code, passed 'crtc' which
@@ -2805,16 +2828,16 @@ static void gen8_disable_vblank(struct drm_device *dev, unsigned int pipe)
 }
 
 static bool
-ring_idle(struct intel_engine_cs *ring, u32 seqno)
+ring_idle(struct intel_engine_cs *engine, u32 seqno)
 {
-       return (list_empty(&ring->request_list) ||
-               i915_seqno_passed(seqno, ring->last_submitted_seqno));
+       return i915_seqno_passed(seqno,
+                                READ_ONCE(engine->last_submitted_seqno));
 }
 
 static bool
-ipehr_is_semaphore_wait(struct drm_device *dev, u32 ipehr)
+ipehr_is_semaphore_wait(struct drm_i915_private *dev_priv, u32 ipehr)
 {
-       if (INTEL_INFO(dev)->gen >= 8) {
+       if (INTEL_GEN(dev_priv) >= 8) {
                return (ipehr >> 23) == 0x1c;
        } else {
                ipehr &= ~MI_SEMAPHORE_SYNC_MASK;
@@ -2824,42 +2847,42 @@ ipehr_is_semaphore_wait(struct drm_device *dev, u32 ipehr)
 }
 
 static struct intel_engine_cs *
-semaphore_wait_to_signaller_ring(struct intel_engine_cs *ring, u32 ipehr, u64 offset)
+semaphore_wait_to_signaller_ring(struct intel_engine_cs *engine, u32 ipehr,
+                                u64 offset)
 {
-       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       struct drm_i915_private *dev_priv = engine->i915;
        struct intel_engine_cs *signaller;
-       int i;
 
-       if (INTEL_INFO(dev_priv->dev)->gen >= 8) {
-               for_each_ring(signaller, dev_priv, i) {
-                       if (ring == signaller)
+       if (INTEL_GEN(dev_priv) >= 8) {
+               for_each_engine(signaller, dev_priv) {
+                       if (engine == signaller)
                                continue;
 
-                       if (offset == signaller->semaphore.signal_ggtt[ring->id])
+                       if (offset == signaller->semaphore.signal_ggtt[engine->id])
                                return signaller;
                }
        } else {
                u32 sync_bits = ipehr & MI_SEMAPHORE_SYNC_MASK;
 
-               for_each_ring(signaller, dev_priv, i) {
-                       if(ring == signaller)
+               for_each_engine(signaller, dev_priv) {
+                       if(engine == signaller)
                                continue;
 
-                       if (sync_bits == signaller->semaphore.mbox.wait[ring->id])
+                       if (sync_bits == signaller->semaphore.mbox.wait[engine->id])
                                return signaller;
                }
        }
 
        DRM_ERROR("No signaller ring found for ring %i, ipehr 0x%08x, offset 0x%016llx\n",
-                 ring->id, ipehr, offset);
+                 engine->id, ipehr, offset);
 
        return NULL;
 }
 
 static struct intel_engine_cs *
-semaphore_waits_for(struct intel_engine_cs *ring, u32 *seqno)
+semaphore_waits_for(struct intel_engine_cs *engine, u32 *seqno)
 {
-       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       struct drm_i915_private *dev_priv = engine->i915;
        u32 cmd, ipehr, head;
        u64 offset = 0;
        int i, backwards;
@@ -2881,11 +2904,11 @@ semaphore_waits_for(struct intel_engine_cs *ring, u32 *seqno)
         * Therefore, this function does not support execlist mode in its
         * current form. Just return NULL and move on.
         */
-       if (ring->buffer == NULL)
+       if (engine->buffer == NULL)
                return NULL;
 
-       ipehr = I915_READ(RING_IPEHR(ring->mmio_base));
-       if (!ipehr_is_semaphore_wait(ring->dev, ipehr))
+       ipehr = I915_READ(RING_IPEHR(engine->mmio_base));
+       if (!ipehr_is_semaphore_wait(engine->i915, ipehr))
                return NULL;
 
        /*
@@ -2896,8 +2919,8 @@ semaphore_waits_for(struct intel_engine_cs *ring, u32 *seqno)
         * point at at batch, and semaphores are always emitted into the
         * ringbuffer itself.
         */
-       head = I915_READ_HEAD(ring) & HEAD_ADDR;
-       backwards = (INTEL_INFO(ring->dev)->gen >= 8) ? 5 : 4;
+       head = I915_READ_HEAD(engine) & HEAD_ADDR;
+       backwards = (INTEL_GEN(dev_priv) >= 8) ? 5 : 4;
 
        for (i = backwards; i; --i) {
                /*
@@ -2905,10 +2928,10 @@ semaphore_waits_for(struct intel_engine_cs *ring, u32 *seqno)
                 * our ring is smaller than what the hardware (and hence
                 * HEAD_ADDR) allows. Also handles wrap-around.
                 */
-               head &= ring->buffer->size - 1;
+               head &= engine->buffer->size - 1;
 
                /* This here seems to blow up */
-               cmd = ioread32(ring->buffer->virtual_start + head);
+               cmd = ioread32(engine->buffer->virtual_start + head);
                if (cmd == ipehr)
                        break;
 
@@ -2918,32 +2941,32 @@ semaphore_waits_for(struct intel_engine_cs *ring, u32 *seqno)
        if (!i)
                return NULL;
 
-       *seqno = ioread32(ring->buffer->virtual_start + head + 4) + 1;
-       if (INTEL_INFO(ring->dev)->gen >= 8) {
-               offset = ioread32(ring->buffer->virtual_start + head + 12);
+       *seqno = ioread32(engine->buffer->virtual_start + head + 4) + 1;
+       if (INTEL_GEN(dev_priv) >= 8) {
+               offset = ioread32(engine->buffer->virtual_start + head + 12);
                offset <<= 32;
-               offset = ioread32(ring->buffer->virtual_start + head + 8);
+               offset = ioread32(engine->buffer->virtual_start + head + 8);
        }
-       return semaphore_wait_to_signaller_ring(ring, ipehr, offset);
+       return semaphore_wait_to_signaller_ring(engine, ipehr, offset);
 }
 
-static int semaphore_passed(struct intel_engine_cs *ring)
+static int semaphore_passed(struct intel_engine_cs *engine)
 {
-       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       struct drm_i915_private *dev_priv = engine->i915;
        struct intel_engine_cs *signaller;
        u32 seqno;
 
-       ring->hangcheck.deadlock++;
+       engine->hangcheck.deadlock++;
 
-       signaller = semaphore_waits_for(ring, &seqno);
+       signaller = semaphore_waits_for(engine, &seqno);
        if (signaller == NULL)
                return -1;
 
        /* Prevent pathological recursion due to driver bugs */
-       if (signaller->hangcheck.deadlock >= I915_NUM_RINGS)
+       if (signaller->hangcheck.deadlock >= I915_NUM_ENGINES)
                return -1;
 
-       if (i915_seqno_passed(signaller->get_seqno(signaller, false), seqno))
+       if (i915_seqno_passed(signaller->get_seqno(signaller), seqno))
                return 1;
 
        /* cursory check for an unkickable deadlock */
@@ -2956,23 +2979,22 @@ static int semaphore_passed(struct intel_engine_cs *ring)
 
 static void semaphore_clear_deadlocks(struct drm_i915_private *dev_priv)
 {
-       struct intel_engine_cs *ring;
-       int i;
+       struct intel_engine_cs *engine;
 
-       for_each_ring(ring, dev_priv, i)
-               ring->hangcheck.deadlock = 0;
+       for_each_engine(engine, dev_priv)
+               engine->hangcheck.deadlock = 0;
 }
 
-static bool subunits_stuck(struct intel_engine_cs *ring)
+static bool subunits_stuck(struct intel_engine_cs *engine)
 {
        u32 instdone[I915_NUM_INSTDONE_REG];
        bool stuck;
        int i;
 
-       if (ring->id != RCS)
+       if (engine->id != RCS)
                return true;
 
-       i915_get_extra_instdone(ring->dev, instdone);
+       i915_get_extra_instdone(engine->i915, instdone);
 
        /* There might be unstable subunit states even when
         * actual head is not moving. Filter out the unstable ones by
@@ -2981,53 +3003,47 @@ static bool subunits_stuck(struct intel_engine_cs *ring)
         */
        stuck = true;
        for (i = 0; i < I915_NUM_INSTDONE_REG; i++) {
-               const u32 tmp = instdone[i] | ring->hangcheck.instdone[i];
+               const u32 tmp = instdone[i] | engine->hangcheck.instdone[i];
 
-               if (tmp != ring->hangcheck.instdone[i])
+               if (tmp != engine->hangcheck.instdone[i])
                        stuck = false;
 
-               ring->hangcheck.instdone[i] |= tmp;
+               engine->hangcheck.instdone[i] |= tmp;
        }
 
        return stuck;
 }
 
 static enum intel_ring_hangcheck_action
-head_stuck(struct intel_engine_cs *ring, u64 acthd)
+head_stuck(struct intel_engine_cs *engine, u64 acthd)
 {
-       if (acthd != ring->hangcheck.acthd) {
+       if (acthd != engine->hangcheck.acthd) {
 
                /* Clear subunit states on head movement */
-               memset(ring->hangcheck.instdone, 0,
-                      sizeof(ring->hangcheck.instdone));
+               memset(engine->hangcheck.instdone, 0,
+                      sizeof(engine->hangcheck.instdone));
 
-               if (acthd > ring->hangcheck.max_acthd) {
-                       ring->hangcheck.max_acthd = acthd;
-                       return HANGCHECK_ACTIVE;
-               }
-
-               return HANGCHECK_ACTIVE_LOOP;
+               return HANGCHECK_ACTIVE;
        }
 
-       if (!subunits_stuck(ring))
+       if (!subunits_stuck(engine))
                return HANGCHECK_ACTIVE;
 
        return HANGCHECK_HUNG;
 }
 
 static enum intel_ring_hangcheck_action
-ring_stuck(struct intel_engine_cs *ring, u64 acthd)
+ring_stuck(struct intel_engine_cs *engine, u64 acthd)
 {
-       struct drm_device *dev = ring->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = engine->i915;
        enum intel_ring_hangcheck_action ha;
        u32 tmp;
 
-       ha = head_stuck(ring, acthd);
+       ha = head_stuck(engine, acthd);
        if (ha != HANGCHECK_HUNG)
                return ha;
 
-       if (IS_GEN2(dev))
+       if (IS_GEN2(dev_priv))
                return HANGCHECK_HUNG;
 
        /* Is the chip hanging on a WAIT_FOR_EVENT?
@@ -3035,24 +3051,24 @@ ring_stuck(struct intel_engine_cs *ring, u64 acthd)
         * and break the hang. This should work on
         * all but the second generation chipsets.
         */
-       tmp = I915_READ_CTL(ring);
+       tmp = I915_READ_CTL(engine);
        if (tmp & RING_WAIT) {
-               i915_handle_error(dev, false,
+               i915_handle_error(dev_priv, 0,
                                  "Kicking stuck wait on %s",
-                                 ring->name);
-               I915_WRITE_CTL(ring, tmp);
+                                 engine->name);
+               I915_WRITE_CTL(engine, tmp);
                return HANGCHECK_KICK;
        }
 
-       if (INTEL_INFO(dev)->gen >= 6 && tmp & RING_WAIT_SEMAPHORE) {
-               switch (semaphore_passed(ring)) {
+       if (INTEL_GEN(dev_priv) >= 6 && tmp & RING_WAIT_SEMAPHORE) {
+               switch (semaphore_passed(engine)) {
                default:
                        return HANGCHECK_HUNG;
                case 1:
-                       i915_handle_error(dev, false,
+                       i915_handle_error(dev_priv, 0,
                                          "Kicking stuck semaphore on %s",
-                                         ring->name);
-                       I915_WRITE_CTL(ring, tmp);
+                                         engine->name);
+                       I915_WRITE_CTL(engine, tmp);
                        return HANGCHECK_KICK;
                case 0:
                        return HANGCHECK_WAIT;
@@ -3062,6 +3078,24 @@ ring_stuck(struct intel_engine_cs *ring, u64 acthd)
        return HANGCHECK_HUNG;
 }
 
+static unsigned kick_waiters(struct intel_engine_cs *engine)
+{
+       struct drm_i915_private *i915 = engine->i915;
+       unsigned user_interrupts = READ_ONCE(engine->user_interrupts);
+
+       if (engine->hangcheck.user_interrupts == user_interrupts &&
+           !test_and_set_bit(engine->id, &i915->gpu_error.missed_irq_rings)) {
+               if (!(i915->gpu_error.test_irq_rings & intel_engine_flag(engine)))
+                       DRM_ERROR("Hangcheck timer elapsed... %s idle\n",
+                                 engine->name);
+               else
+                       DRM_INFO("Fake missed irq on %s\n",
+                                engine->name);
+               wake_up_all(&engine->irq_queue);
+       }
+
+       return user_interrupts;
+}
 /*
  * This is called when the chip hasn't reported back with completed
  * batchbuffers in a long time. We keep track per ring seqno progress and
@@ -3075,14 +3109,14 @@ static void i915_hangcheck_elapsed(struct work_struct *work)
        struct drm_i915_private *dev_priv =
                container_of(work, typeof(*dev_priv),
                             gpu_error.hangcheck_work.work);
-       struct drm_device *dev = dev_priv->dev;
-       struct intel_engine_cs *ring;
-       int i;
+       struct intel_engine_cs *engine;
+       enum intel_engine_id id;
        int busy_count = 0, rings_hung = 0;
-       bool stuck[I915_NUM_RINGS] = { 0 };
+       bool stuck[I915_NUM_ENGINES] = { 0 };
 #define BUSY 1
 #define KICK 5
 #define HUNG 20
+#define ACTIVE_DECAY 15
 
        if (!i915.enable_hangcheck)
                return;
@@ -3100,35 +3134,38 @@ static void i915_hangcheck_elapsed(struct work_struct *work)
         */
        intel_uncore_arm_unclaimed_mmio_detection(dev_priv);
 
-       for_each_ring(ring, dev_priv, i) {
+       for_each_engine_id(engine, dev_priv, id) {
+               bool busy = waitqueue_active(&engine->irq_queue);
                u64 acthd;
                u32 seqno;
-               bool busy = true;
+               unsigned user_interrupts;
 
                semaphore_clear_deadlocks(dev_priv);
 
-               seqno = ring->get_seqno(ring, false);
-               acthd = intel_ring_get_active_head(ring);
-
-               if (ring->hangcheck.seqno == seqno) {
-                       if (ring_idle(ring, seqno)) {
-                               ring->hangcheck.action = HANGCHECK_IDLE;
-
-                               if (waitqueue_active(&ring->irq_queue)) {
-                                       /* Issue a wake-up to catch stuck h/w. */
-                                       if (!test_and_set_bit(ring->id, &dev_priv->gpu_error.missed_irq_rings)) {
-                                               if (!(dev_priv->gpu_error.test_irq_rings & intel_ring_flag(ring)))
-                                                       DRM_ERROR("Hangcheck timer elapsed... %s idle\n",
-                                                                 ring->name);
-                                               else
-                                                       DRM_INFO("Fake missed irq on %s\n",
-                                                                ring->name);
-                                               wake_up_all(&ring->irq_queue);
-                                       }
+               /* We don't strictly need an irq-barrier here, as we are not
+                * serving an interrupt request, be paranoid in case the
+                * barrier has side-effects (such as preventing a broken
+                * cacheline snoop) and so be sure that we can see the seqno
+                * advance. If the seqno should stick, due to a stale
+                * cacheline, we would erroneously declare the GPU hung.
+                */
+               if (engine->irq_seqno_barrier)
+                       engine->irq_seqno_barrier(engine);
+
+               acthd = intel_ring_get_active_head(engine);
+               seqno = engine->get_seqno(engine);
+
+               /* Reset stuck interrupts between batch advances */
+               user_interrupts = 0;
+
+               if (engine->hangcheck.seqno == seqno) {
+                       if (ring_idle(engine, seqno)) {
+                               engine->hangcheck.action = HANGCHECK_IDLE;
+                               if (busy) {
                                        /* Safeguard against driver failure */
-                                       ring->hangcheck.score += BUSY;
-                               } else
-                                       busy = false;
+                                       user_interrupts = kick_waiters(engine);
+                                       engine->hangcheck.score += BUSY;
+                               }
                        } else {
                                /* We always increment the hangcheck score
                                 * if the ring is busy and still processing
@@ -3145,73 +3182,74 @@ static void i915_hangcheck_elapsed(struct work_struct *work)
                                 * being repeatedly kicked and so responsible
                                 * for stalling the machine.
                                 */
-                               ring->hangcheck.action = ring_stuck(ring,
-                                                                   acthd);
+                               engine->hangcheck.action = ring_stuck(engine,
+                                                                     acthd);
 
-                               switch (ring->hangcheck.action) {
+                               switch (engine->hangcheck.action) {
                                case HANGCHECK_IDLE:
                                case HANGCHECK_WAIT:
-                               case HANGCHECK_ACTIVE:
                                        break;
-                               case HANGCHECK_ACTIVE_LOOP:
-                                       ring->hangcheck.score += BUSY;
+                               case HANGCHECK_ACTIVE:
+                                       engine->hangcheck.score += BUSY;
                                        break;
                                case HANGCHECK_KICK:
-                                       ring->hangcheck.score += KICK;
+                                       engine->hangcheck.score += KICK;
                                        break;
                                case HANGCHECK_HUNG:
-                                       ring->hangcheck.score += HUNG;
-                                       stuck[i] = true;
+                                       engine->hangcheck.score += HUNG;
+                                       stuck[id] = true;
                                        break;
                                }
                        }
                } else {
-                       ring->hangcheck.action = HANGCHECK_ACTIVE;
+                       engine->hangcheck.action = HANGCHECK_ACTIVE;
 
                        /* Gradually reduce the count so that we catch DoS
                         * attempts across multiple batches.
                         */
-                       if (ring->hangcheck.score > 0)
-                               ring->hangcheck.score--;
+                       if (engine->hangcheck.score > 0)
+                               engine->hangcheck.score -= ACTIVE_DECAY;
+                       if (engine->hangcheck.score < 0)
+                               engine->hangcheck.score = 0;
 
                        /* Clear head and subunit states on seqno movement */
-                       ring->hangcheck.acthd = ring->hangcheck.max_acthd = 0;
+                       acthd = 0;
 
-                       memset(ring->hangcheck.instdone, 0,
-                              sizeof(ring->hangcheck.instdone));
+                       memset(engine->hangcheck.instdone, 0,
+                              sizeof(engine->hangcheck.instdone));
                }
 
-               ring->hangcheck.seqno = seqno;
-               ring->hangcheck.acthd = acthd;
+               engine->hangcheck.seqno = seqno;
+               engine->hangcheck.acthd = acthd;
+               engine->hangcheck.user_interrupts = user_interrupts;
                busy_count += busy;
        }
 
-       for_each_ring(ring, dev_priv, i) {
-               if (ring->hangcheck.score >= HANGCHECK_SCORE_RING_HUNG) {
+       for_each_engine_id(engine, dev_priv, id) {
+               if (engine->hangcheck.score >= HANGCHECK_SCORE_RING_HUNG) {
                        DRM_INFO("%s on %s\n",
-                                stuck[i] ? "stuck" : "no progress",
-                                ring->name);
-                       rings_hung++;
+                                stuck[id] ? "stuck" : "no progress",
+                                engine->name);
+                       rings_hung |= intel_engine_flag(engine);
                }
        }
 
        if (rings_hung) {
-               i915_handle_error(dev, true, "Ring hung");
+               i915_handle_error(dev_priv, rings_hung, "Engine(s) hung");
                goto out;
        }
 
+       /* Reset timer in case GPU hangs without another request being added */
        if (busy_count)
-               /* Reset timer case chip hangs without another request
-                * being added */
-               i915_queue_hangcheck(dev);
+               i915_queue_hangcheck(dev_priv);
 
 out:
        ENABLE_RPM_WAKEREF_ASSERTS(dev_priv);
 }
 
-void i915_queue_hangcheck(struct drm_device *dev)
+void i915_queue_hangcheck(struct drm_i915_private *dev_priv)
 {
-       struct i915_gpu_error *e = &to_i915(dev)->gpu_error;
+       struct i915_gpu_error *e = &dev_priv->gpu_error;
 
        if (!i915.enable_hangcheck)
                return;
@@ -3267,6 +3305,55 @@ static void gen5_gt_irq_reset(struct drm_device *dev)
                GEN5_IRQ_RESET(GEN6_PM);
 }
 
+static void vlv_display_irq_reset(struct drm_i915_private *dev_priv)
+{
+       enum pipe pipe;
+
+       if (IS_CHERRYVIEW(dev_priv))
+               I915_WRITE(DPINVGTT, DPINVGTT_STATUS_MASK_CHV);
+       else
+               I915_WRITE(DPINVGTT, DPINVGTT_STATUS_MASK);
+
+       i915_hotplug_interrupt_update_locked(dev_priv, 0xffffffff, 0);
+       I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
+
+       for_each_pipe(dev_priv, pipe) {
+               I915_WRITE(PIPESTAT(pipe),
+                          PIPE_FIFO_UNDERRUN_STATUS |
+                          PIPESTAT_INT_STATUS_MASK);
+               dev_priv->pipestat_irq_mask[pipe] = 0;
+       }
+
+       GEN5_IRQ_RESET(VLV_);
+       dev_priv->irq_mask = ~0;
+}
+
+static void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv)
+{
+       u32 pipestat_mask;
+       u32 enable_mask;
+       enum pipe pipe;
+
+       pipestat_mask = PLANE_FLIP_DONE_INT_STATUS_VLV |
+                       PIPE_CRC_DONE_INTERRUPT_STATUS;
+
+       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS);
+       for_each_pipe(dev_priv, pipe)
+               i915_enable_pipestat(dev_priv, pipe, pipestat_mask);
+
+       enable_mask = I915_DISPLAY_PORT_INTERRUPT |
+               I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
+               I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
+       if (IS_CHERRYVIEW(dev_priv))
+               enable_mask |= I915_DISPLAY_PIPE_C_EVENT_INTERRUPT;
+
+       WARN_ON(dev_priv->irq_mask != ~0);
+
+       dev_priv->irq_mask = ~enable_mask;
+
+       GEN5_IRQ_INIT(VLV_, dev_priv->irq_mask, enable_mask);
+}
+
 /* drm_dma.h hooks
 */
 static void ironlake_irq_reset(struct drm_device *dev)
@@ -3284,34 +3371,19 @@ static void ironlake_irq_reset(struct drm_device *dev)
        ibx_irq_reset(dev);
 }
 
-static void vlv_display_irq_reset(struct drm_i915_private *dev_priv)
-{
-       enum pipe pipe;
-
-       i915_hotplug_interrupt_update(dev_priv, 0xFFFFFFFF, 0);
-       I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
-
-       for_each_pipe(dev_priv, pipe)
-               I915_WRITE(PIPESTAT(pipe), 0xffff);
-
-       GEN5_IRQ_RESET(VLV_);
-}
-
 static void valleyview_irq_preinstall(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       /* VLV magic */
-       I915_WRITE(VLV_IMR, 0);
-       I915_WRITE(RING_IMR(RENDER_RING_BASE), 0);
-       I915_WRITE(RING_IMR(GEN6_BSD_RING_BASE), 0);
-       I915_WRITE(RING_IMR(BLT_RING_BASE), 0);
+       I915_WRITE(VLV_MASTER_IER, 0);
+       POSTING_READ(VLV_MASTER_IER);
 
        gen5_gt_irq_reset(dev);
 
-       I915_WRITE(DPINVGTT, DPINVGTT_STATUS_MASK);
-
-       vlv_display_irq_reset(dev_priv);
+       spin_lock_irq(&dev_priv->irq_lock);
+       if (dev_priv->display_irqs_enabled)
+               vlv_display_irq_reset(dev_priv);
+       spin_unlock_irq(&dev_priv->irq_lock);
 }
 
 static void gen8_gt_irq_reset(struct drm_i915_private *dev_priv)
@@ -3384,36 +3456,35 @@ static void cherryview_irq_preinstall(struct drm_device *dev)
 
        GEN5_IRQ_RESET(GEN8_PCU_);
 
-       I915_WRITE(DPINVGTT, DPINVGTT_STATUS_MASK_CHV);
-
-       vlv_display_irq_reset(dev_priv);
+       spin_lock_irq(&dev_priv->irq_lock);
+       if (dev_priv->display_irqs_enabled)
+               vlv_display_irq_reset(dev_priv);
+       spin_unlock_irq(&dev_priv->irq_lock);
 }
 
-static u32 intel_hpd_enabled_irqs(struct drm_device *dev,
+static u32 intel_hpd_enabled_irqs(struct drm_i915_private *dev_priv,
                                  const u32 hpd[HPD_NUM_PINS])
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_encoder *encoder;
        u32 enabled_irqs = 0;
 
-       for_each_intel_encoder(dev, encoder)
+       for_each_intel_encoder(dev_priv->dev, encoder)
                if (dev_priv->hotplug.stats[encoder->hpd_pin].state == HPD_ENABLED)
                        enabled_irqs |= hpd[encoder->hpd_pin];
 
        return enabled_irqs;
 }
 
-static void ibx_hpd_irq_setup(struct drm_device *dev)
+static void ibx_hpd_irq_setup(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 hotplug_irqs, hotplug, enabled_irqs;
 
-       if (HAS_PCH_IBX(dev)) {
+       if (HAS_PCH_IBX(dev_priv)) {
                hotplug_irqs = SDE_HOTPLUG_MASK;
-               enabled_irqs = intel_hpd_enabled_irqs(dev, hpd_ibx);
+               enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_ibx);
        } else {
                hotplug_irqs = SDE_HOTPLUG_MASK_CPT;
-               enabled_irqs = intel_hpd_enabled_irqs(dev, hpd_cpt);
+               enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_cpt);
        }
 
        ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs);
@@ -3432,18 +3503,17 @@ static void ibx_hpd_irq_setup(struct drm_device *dev)
         * When CPU and PCH are on the same package, port A
         * HPD must be enabled in both north and south.
         */
-       if (HAS_PCH_LPT_LP(dev))
+       if (HAS_PCH_LPT_LP(dev_priv))
                hotplug |= PORTA_HOTPLUG_ENABLE;
        I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
 }
 
-static void spt_hpd_irq_setup(struct drm_device *dev)
+static void spt_hpd_irq_setup(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 hotplug_irqs, hotplug, enabled_irqs;
 
        hotplug_irqs = SDE_HOTPLUG_MASK_SPT;
-       enabled_irqs = intel_hpd_enabled_irqs(dev, hpd_spt);
+       enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_spt);
 
        ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs);
 
@@ -3458,24 +3528,23 @@ static void spt_hpd_irq_setup(struct drm_device *dev)
        I915_WRITE(PCH_PORT_HOTPLUG2, hotplug);
 }
 
-static void ilk_hpd_irq_setup(struct drm_device *dev)
+static void ilk_hpd_irq_setup(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 hotplug_irqs, hotplug, enabled_irqs;
 
-       if (INTEL_INFO(dev)->gen >= 8) {
+       if (INTEL_GEN(dev_priv) >= 8) {
                hotplug_irqs = GEN8_PORT_DP_A_HOTPLUG;
-               enabled_irqs = intel_hpd_enabled_irqs(dev, hpd_bdw);
+               enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_bdw);
 
                bdw_update_port_irq(dev_priv, hotplug_irqs, enabled_irqs);
-       } else if (INTEL_INFO(dev)->gen >= 7) {
+       } else if (INTEL_GEN(dev_priv) >= 7) {
                hotplug_irqs = DE_DP_A_HOTPLUG_IVB;
-               enabled_irqs = intel_hpd_enabled_irqs(dev, hpd_ivb);
+               enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_ivb);
 
                ilk_update_display_irq(dev_priv, hotplug_irqs, enabled_irqs);
        } else {
                hotplug_irqs = DE_DP_A_HOTPLUG;
-               enabled_irqs = intel_hpd_enabled_irqs(dev, hpd_ilk);
+               enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_ilk);
 
                ilk_update_display_irq(dev_priv, hotplug_irqs, enabled_irqs);
        }
@@ -3490,15 +3559,14 @@ static void ilk_hpd_irq_setup(struct drm_device *dev)
        hotplug |= DIGITAL_PORTA_HOTPLUG_ENABLE | DIGITAL_PORTA_PULSE_DURATION_2ms;
        I915_WRITE(DIGITAL_PORT_HOTPLUG_CNTRL, hotplug);
 
-       ibx_hpd_irq_setup(dev);
+       ibx_hpd_irq_setup(dev_priv);
 }
 
-static void bxt_hpd_irq_setup(struct drm_device *dev)
+static void bxt_hpd_irq_setup(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 hotplug_irqs, hotplug, enabled_irqs;
 
-       enabled_irqs = intel_hpd_enabled_irqs(dev, hpd_bxt);
+       enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_bxt);
        hotplug_irqs = BXT_DE_PORT_HOTPLUG_MASK;
 
        bdw_update_port_irq(dev_priv, hotplug_irqs, enabled_irqs);
@@ -3506,6 +3574,26 @@ static void bxt_hpd_irq_setup(struct drm_device *dev)
        hotplug = I915_READ(PCH_PORT_HOTPLUG);
        hotplug |= PORTC_HOTPLUG_ENABLE | PORTB_HOTPLUG_ENABLE |
                PORTA_HOTPLUG_ENABLE;
+
+       DRM_DEBUG_KMS("Invert bit setting: hp_ctl:%x hp_port:%x\n",
+                     hotplug, enabled_irqs);
+       hotplug &= ~BXT_DDI_HPD_INVERT_MASK;
+
+       /*
+        * For BXT invert bit has to be set based on AOB design
+        * for HPD detection logic, update it based on VBT fields.
+        */
+
+       if ((enabled_irqs & BXT_DE_PORT_HP_DDIA) &&
+           intel_bios_is_port_hpd_inverted(dev_priv, PORT_A))
+               hotplug |= BXT_DDIA_HPD_INVERT;
+       if ((enabled_irqs & BXT_DE_PORT_HP_DDIB) &&
+           intel_bios_is_port_hpd_inverted(dev_priv, PORT_B))
+               hotplug |= BXT_DDIB_HPD_INVERT;
+       if ((enabled_irqs & BXT_DE_PORT_HP_DDIC) &&
+           intel_bios_is_port_hpd_inverted(dev_priv, PORT_C))
+               hotplug |= BXT_DDIC_HPD_INVERT;
+
        I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
 }
 
@@ -3613,74 +3701,6 @@ 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;
-       enum pipe pipe;
-
-       pipestat_mask = PIPESTAT_INT_STATUS_MASK |
-                       PIPE_FIFO_UNDERRUN_STATUS;
-
-       for_each_pipe(dev_priv, pipe)
-               I915_WRITE(PIPESTAT(pipe), 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, PIPE_GMBUS_INTERRUPT_STATUS);
-       for_each_pipe(dev_priv, pipe)
-                     i915_enable_pipestat(dev_priv, pipe, pipestat_mask);
-
-       iir_mask = I915_DISPLAY_PORT_INTERRUPT |
-                  I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
-                  I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
-       if (IS_CHERRYVIEW(dev_priv))
-               iir_mask |= I915_DISPLAY_PIPE_C_EVENT_INTERRUPT;
-       dev_priv->irq_mask &= ~iir_mask;
-
-       I915_WRITE(VLV_IIR, iir_mask);
-       I915_WRITE(VLV_IIR, iir_mask);
-       I915_WRITE(VLV_IER, ~dev_priv->irq_mask);
-       I915_WRITE(VLV_IMR, dev_priv->irq_mask);
-       POSTING_READ(VLV_IMR);
-}
-
-static void valleyview_display_irqs_uninstall(struct drm_i915_private *dev_priv)
-{
-       u32 pipestat_mask;
-       u32 iir_mask;
-       enum pipe pipe;
-
-       iir_mask = I915_DISPLAY_PORT_INTERRUPT |
-                  I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
-                  I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
-       if (IS_CHERRYVIEW(dev_priv))
-               iir_mask |= I915_DISPLAY_PIPE_C_EVENT_INTERRUPT;
-
-       dev_priv->irq_mask |= iir_mask;
-       I915_WRITE(VLV_IMR, dev_priv->irq_mask);
-       I915_WRITE(VLV_IER, ~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, PIPE_GMBUS_INTERRUPT_STATUS);
-       for_each_pipe(dev_priv, pipe)
-               i915_disable_pipestat(dev_priv, pipe, pipestat_mask);
-
-       pipestat_mask = PIPESTAT_INT_STATUS_MASK |
-                       PIPE_FIFO_UNDERRUN_STATUS;
-
-       for_each_pipe(dev_priv, pipe)
-               I915_WRITE(PIPESTAT(pipe), 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);
@@ -3690,8 +3710,10 @@ void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv)
 
        dev_priv->display_irqs_enabled = true;
 
-       if (intel_irqs_enabled(dev_priv))
-               valleyview_display_irqs_install(dev_priv);
+       if (intel_irqs_enabled(dev_priv)) {
+               vlv_display_irq_reset(dev_priv);
+               vlv_display_irq_postinstall(dev_priv);
+       }
 }
 
 void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv)
@@ -3704,45 +3726,23 @@ void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv)
        dev_priv->display_irqs_enabled = false;
 
        if (intel_irqs_enabled(dev_priv))
-               valleyview_display_irqs_uninstall(dev_priv);
+               vlv_display_irq_reset(dev_priv);
 }
 
-static void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv)
-{
-       dev_priv->irq_mask = ~0;
-
-       i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0);
-       POSTING_READ(PORT_HOTPLUG_EN);
-
-       I915_WRITE(VLV_IIR, 0xffffffff);
-       I915_WRITE(VLV_IIR, 0xffffffff);
-       I915_WRITE(VLV_IER, ~dev_priv->irq_mask);
-       I915_WRITE(VLV_IMR, dev_priv->irq_mask);
-       POSTING_READ(VLV_IMR);
-
-       /* Interrupt setup is already guaranteed to be single-threaded, this is
-        * just to make the assert_spin_locked check happy. */
-       spin_lock_irq(&dev_priv->irq_lock);
-       if (dev_priv->display_irqs_enabled)
-               valleyview_display_irqs_install(dev_priv);
-       spin_unlock_irq(&dev_priv->irq_lock);
-}
 
 static int valleyview_irq_postinstall(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       vlv_display_irq_postinstall(dev_priv);
-
        gen5_gt_irq_postinstall(dev);
 
-       /* ack & enable invalid PTE error interrupts */
-#if 0 /* FIXME: add support to irq handler for checking these bits */
-       I915_WRITE(DPINVGTT, DPINVGTT_STATUS_MASK);
-       I915_WRITE(DPINVGTT, DPINVGTT_EN_MASK);
-#endif
+       spin_lock_irq(&dev_priv->irq_lock);
+       if (dev_priv->display_irqs_enabled)
+               vlv_display_irq_postinstall(dev_priv);
+       spin_unlock_irq(&dev_priv->irq_lock);
 
        I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE);
+       POSTING_READ(VLV_MASTER_IER);
 
        return 0;
 }
@@ -3753,7 +3753,6 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
        uint32_t gt_interrupts[] = {
                GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
                        GT_CONTEXT_SWITCH_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
-                       GT_RENDER_L3_PARITY_ERROR_INTERRUPT |
                        GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT |
                        GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT,
                GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT |
@@ -3765,6 +3764,9 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
                        GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT
                };
 
+       if (HAS_L3_DPF(dev_priv))
+               gt_interrupts[0] |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
+
        dev_priv->pm_irq_mask = 0xffffffff;
        GEN8_IRQ_INIT_NDX(GT, 0, ~gt_interrupts[0], gt_interrupts[0]);
        GEN8_IRQ_INIT_NDX(GT, 1, ~gt_interrupts[1], gt_interrupts[1]);
@@ -3782,6 +3784,7 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
        uint32_t de_pipe_enables;
        u32 de_port_masked = GEN8_AUX_CHANNEL_A;
        u32 de_port_enables;
+       u32 de_misc_masked = GEN8_DE_MISC_GSE;
        enum pipe pipe;
 
        if (INTEL_INFO(dev_priv)->gen >= 9) {
@@ -3817,6 +3820,7 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
                                          de_pipe_enables);
 
        GEN5_IRQ_INIT(GEN8_DE_PORT_, ~de_port_masked, de_port_enables);
+       GEN5_IRQ_INIT(GEN8_DE_MISC_, ~de_misc_masked, de_misc_masked);
 }
 
 static int gen8_irq_postinstall(struct drm_device *dev)
@@ -3832,7 +3836,7 @@ static int gen8_irq_postinstall(struct drm_device *dev)
        if (HAS_PCH_SPLIT(dev))
                ibx_irq_postinstall(dev);
 
-       I915_WRITE(GEN8_MASTER_IRQ, DE_MASTER_IRQ_CONTROL);
+       I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
        POSTING_READ(GEN8_MASTER_IRQ);
 
        return 0;
@@ -3842,11 +3846,14 @@ static int cherryview_irq_postinstall(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       vlv_display_irq_postinstall(dev_priv);
-
        gen8_gt_irq_postinstall(dev_priv);
 
-       I915_WRITE(GEN8_MASTER_IRQ, MASTER_INTERRUPT_ENABLE);
+       spin_lock_irq(&dev_priv->irq_lock);
+       if (dev_priv->display_irqs_enabled)
+               vlv_display_irq_postinstall(dev_priv);
+       spin_unlock_irq(&dev_priv->irq_lock);
+
+       I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
        POSTING_READ(GEN8_MASTER_IRQ);
 
        return 0;
@@ -3862,20 +3869,6 @@ static void gen8_irq_uninstall(struct drm_device *dev)
        gen8_irq_reset(dev);
 }
 
-static void vlv_display_irq_uninstall(struct drm_i915_private *dev_priv)
-{
-       /* Interrupt setup is already guaranteed to be single-threaded, this is
-        * just to make the assert_spin_locked check happy. */
-       spin_lock_irq(&dev_priv->irq_lock);
-       if (dev_priv->display_irqs_enabled)
-               valleyview_display_irqs_uninstall(dev_priv);
-       spin_unlock_irq(&dev_priv->irq_lock);
-
-       vlv_display_irq_reset(dev_priv);
-
-       dev_priv->irq_mask = ~0;
-}
-
 static void valleyview_irq_uninstall(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3884,12 +3877,16 @@ static void valleyview_irq_uninstall(struct drm_device *dev)
                return;
 
        I915_WRITE(VLV_MASTER_IER, 0);
+       POSTING_READ(VLV_MASTER_IER);
 
        gen5_gt_irq_reset(dev);
 
        I915_WRITE(HWSTAM, 0xffffffff);
 
-       vlv_display_irq_uninstall(dev_priv);
+       spin_lock_irq(&dev_priv->irq_lock);
+       if (dev_priv->display_irqs_enabled)
+               vlv_display_irq_reset(dev_priv);
+       spin_unlock_irq(&dev_priv->irq_lock);
 }
 
 static void cherryview_irq_uninstall(struct drm_device *dev)
@@ -3906,7 +3903,10 @@ static void cherryview_irq_uninstall(struct drm_device *dev)
 
        GEN5_IRQ_RESET(GEN8_PCU_);
 
-       vlv_display_irq_uninstall(dev_priv);
+       spin_lock_irq(&dev_priv->irq_lock);
+       if (dev_priv->display_irqs_enabled)
+               vlv_display_irq_reset(dev_priv);
+       spin_unlock_irq(&dev_priv->irq_lock);
 }
 
 static void ironlake_irq_uninstall(struct drm_device *dev)
@@ -3965,13 +3965,12 @@ static int i8xx_irq_postinstall(struct drm_device *dev)
 /*
  * Returns true when a page flip has completed.
  */
-static bool i8xx_handle_vblank(struct drm_device *dev,
+static bool i8xx_handle_vblank(struct drm_i915_private *dev_priv,
                               int plane, int pipe, u32 iir)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane);
 
-       if (!intel_pipe_handle_vblank(dev, pipe))
+       if (!intel_pipe_handle_vblank(dev_priv, pipe))
                return false;
 
        if ((iir & flip_pending) == 0)
@@ -3986,12 +3985,11 @@ static bool i8xx_handle_vblank(struct drm_device *dev,
        if (I915_READ16(ISR) & flip_pending)
                goto check_page_flip;
 
-       intel_prepare_page_flip(dev, plane);
-       intel_finish_page_flip(dev, pipe);
+       intel_finish_page_flip_cs(dev_priv, pipe);
        return true;
 
 check_page_flip:
-       intel_check_page_flip(dev, pipe);
+       intel_check_page_flip(dev_priv, pipe);
        return false;
 }
 
@@ -4044,19 +4042,19 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
                new_iir = I915_READ16(IIR); /* Flush posted writes */
 
                if (iir & I915_USER_INTERRUPT)
-                       notify_ring(&dev_priv->ring[RCS]);
+                       notify_ring(&dev_priv->engine[RCS]);
 
                for_each_pipe(dev_priv, pipe) {
                        int plane = pipe;
-                       if (HAS_FBC(dev))
+                       if (HAS_FBC(dev_priv))
                                plane = !plane;
 
                        if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS &&
-                           i8xx_handle_vblank(dev, plane, pipe, iir))
+                           i8xx_handle_vblank(dev_priv, plane, pipe, iir))
                                flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(plane);
 
                        if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
-                               i9xx_pipe_crc_irq_handler(dev, pipe);
+                               i9xx_pipe_crc_irq_handler(dev_priv, pipe);
 
                        if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
                                intel_cpu_fifo_underrun_irq_handler(dev_priv,
@@ -4141,7 +4139,7 @@ static int i915_irq_postinstall(struct drm_device *dev)
        I915_WRITE(IER, enable_mask);
        POSTING_READ(IER);
 
-       i915_enable_asle_pipestat(dev);
+       i915_enable_asle_pipestat(dev_priv);
 
        /* Interrupt setup is already guaranteed to be single-threaded, this is
         * just to make the assert_spin_locked check happy. */
@@ -4156,13 +4154,12 @@ static int i915_irq_postinstall(struct drm_device *dev)
 /*
  * Returns true when a page flip has completed.
  */
-static bool i915_handle_vblank(struct drm_device *dev,
+static bool i915_handle_vblank(struct drm_i915_private *dev_priv,
                               int plane, int pipe, u32 iir)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane);
 
-       if (!intel_pipe_handle_vblank(dev, pipe))
+       if (!intel_pipe_handle_vblank(dev_priv, pipe))
                return false;
 
        if ((iir & flip_pending) == 0)
@@ -4177,12 +4174,11 @@ static bool i915_handle_vblank(struct drm_device *dev,
        if (I915_READ(ISR) & flip_pending)
                goto check_page_flip;
 
-       intel_prepare_page_flip(dev, plane);
-       intel_finish_page_flip(dev, pipe);
+       intel_finish_page_flip_cs(dev_priv, pipe);
        return true;
 
 check_page_flip:
-       intel_check_page_flip(dev, pipe);
+       intel_check_page_flip(dev_priv, pipe);
        return false;
 }
 
@@ -4232,30 +4228,33 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
                        break;
 
                /* Consume port.  Then clear IIR or we'll miss events */
-               if (I915_HAS_HOTPLUG(dev) &&
-                   iir & I915_DISPLAY_PORT_INTERRUPT)
-                       i9xx_hpd_irq_handler(dev);
+               if (I915_HAS_HOTPLUG(dev_priv) &&
+                   iir & I915_DISPLAY_PORT_INTERRUPT) {
+                       u32 hotplug_status = i9xx_hpd_irq_ack(dev_priv);
+                       if (hotplug_status)
+                               i9xx_hpd_irq_handler(dev_priv, hotplug_status);
+               }
 
                I915_WRITE(IIR, iir & ~flip_mask);
                new_iir = I915_READ(IIR); /* Flush posted writes */
 
                if (iir & I915_USER_INTERRUPT)
-                       notify_ring(&dev_priv->ring[RCS]);
+                       notify_ring(&dev_priv->engine[RCS]);
 
                for_each_pipe(dev_priv, pipe) {
                        int plane = pipe;
-                       if (HAS_FBC(dev))
+                       if (HAS_FBC(dev_priv))
                                plane = !plane;
 
                        if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS &&
-                           i915_handle_vblank(dev, plane, pipe, iir))
+                           i915_handle_vblank(dev_priv, plane, pipe, iir))
                                flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(plane);
 
                        if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
                                blc_event = true;
 
                        if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
-                               i9xx_pipe_crc_irq_handler(dev, pipe);
+                               i9xx_pipe_crc_irq_handler(dev_priv, pipe);
 
                        if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
                                intel_cpu_fifo_underrun_irq_handler(dev_priv,
@@ -4263,7 +4262,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
                }
 
                if (blc_event || (iir & I915_ASLE_INTERRUPT))
-                       intel_opregion_asle_intr(dev);
+                       intel_opregion_asle_intr(dev_priv);
 
                /* With MSI, interrupts are only generated when iir
                 * transitions from zero to nonzero.  If another bit got
@@ -4347,7 +4346,7 @@ static int i965_irq_postinstall(struct drm_device *dev)
                         I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT);
        enable_mask |= I915_USER_INTERRUPT;
 
-       if (IS_G4X(dev))
+       if (IS_G4X(dev_priv))
                enable_mask |= I915_BSD_USER_INTERRUPT;
 
        /* Interrupt setup is already guaranteed to be single-threaded, this is
@@ -4362,7 +4361,7 @@ static int i965_irq_postinstall(struct drm_device *dev)
         * Enable some error detection, note the instruction error mask
         * bit is reserved, so we leave it masked.
         */
-       if (IS_G4X(dev)) {
+       if (IS_G4X(dev_priv)) {
                error_mask = ~(GM45_ERROR_PAGE_TABLE |
                               GM45_ERROR_MEM_PRIV |
                               GM45_ERROR_CP_PRIV |
@@ -4380,26 +4379,25 @@ static int i965_irq_postinstall(struct drm_device *dev)
        i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0);
        POSTING_READ(PORT_HOTPLUG_EN);
 
-       i915_enable_asle_pipestat(dev);
+       i915_enable_asle_pipestat(dev_priv);
 
        return 0;
 }
 
-static void i915_hpd_irq_setup(struct drm_device *dev)
+static void i915_hpd_irq_setup(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 hotplug_en;
 
        assert_spin_locked(&dev_priv->irq_lock);
 
        /* Note HDMI and DP share hotplug bits */
        /* enable bits are the same for all generations */
-       hotplug_en = intel_hpd_enabled_irqs(dev, hpd_mask_i915);
+       hotplug_en = intel_hpd_enabled_irqs(dev_priv, hpd_mask_i915);
        /* Programming the CRT detection parameters tends
           to generate a spurious hotplug event about three
           seconds later.  So just do it once.
        */
-       if (IS_G4X(dev))
+       if (IS_G4X(dev_priv))
                hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64;
        hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
 
@@ -4463,37 +4461,40 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
                ret = IRQ_HANDLED;
 
                /* Consume port.  Then clear IIR or we'll miss events */
-               if (iir & I915_DISPLAY_PORT_INTERRUPT)
-                       i9xx_hpd_irq_handler(dev);
+               if (iir & I915_DISPLAY_PORT_INTERRUPT) {
+                       u32 hotplug_status = i9xx_hpd_irq_ack(dev_priv);
+                       if (hotplug_status)
+                               i9xx_hpd_irq_handler(dev_priv, hotplug_status);
+               }
 
                I915_WRITE(IIR, iir & ~flip_mask);
                new_iir = I915_READ(IIR); /* Flush posted writes */
 
                if (iir & I915_USER_INTERRUPT)
-                       notify_ring(&dev_priv->ring[RCS]);
+                       notify_ring(&dev_priv->engine[RCS]);
                if (iir & I915_BSD_USER_INTERRUPT)
-                       notify_ring(&dev_priv->ring[VCS]);
+                       notify_ring(&dev_priv->engine[VCS]);
 
                for_each_pipe(dev_priv, pipe) {
                        if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS &&
-                           i915_handle_vblank(dev, pipe, pipe, iir))
+                           i915_handle_vblank(dev_priv, pipe, pipe, iir))
                                flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(pipe);
 
                        if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
                                blc_event = true;
 
                        if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
-                               i9xx_pipe_crc_irq_handler(dev, pipe);
+                               i9xx_pipe_crc_irq_handler(dev_priv, pipe);
 
                        if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
                                intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
                }
 
                if (blc_event || (iir & I915_ASLE_INTERRUPT))
-                       intel_opregion_asle_intr(dev);
+                       intel_opregion_asle_intr(dev_priv);
 
                if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
-                       gmbus_irq_handler(dev);
+                       gmbus_irq_handler(dev_priv);
 
                /* With MSI, interrupts are only generated when iir
                 * transitions from zero to nonzero.  If another bit got
@@ -4564,11 +4565,23 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
        else
                dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS;
 
+       dev_priv->rps.pm_intr_keep = 0;
+
+       /*
+        * SNB,IVB can while VLV,CHV may hard hang on looping batchbuffer
+        * if GEN6_PM_UP_EI_EXPIRED is masked.
+        *
+        * TODO: verify if this can be reproduced on VLV,CHV.
+        */
+       if (INTEL_INFO(dev_priv)->gen <= 7 && !IS_HASWELL(dev_priv))
+               dev_priv->rps.pm_intr_keep |= GEN6_PM_RP_UP_EI_EXPIRED;
+
+       if (INTEL_INFO(dev_priv)->gen >= 8)
+               dev_priv->rps.pm_intr_keep |= GEN8_PMINTR_REDIRECT_TO_NON_DISP;
+
        INIT_DELAYED_WORK(&dev_priv->gpu_error.hangcheck_work,
                          i915_hangcheck_elapsed);
 
-       pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
-
        if (IS_GEN2(dev_priv)) {
                dev->max_vblank_count = 0;
                dev->driver->get_vblank_counter = i8xx_get_vblank_counter;
@@ -4629,12 +4642,12 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
                dev->driver->disable_vblank = ironlake_disable_vblank;
                dev_priv->display.hpd_irq_setup = ilk_hpd_irq_setup;
        } else {
-               if (INTEL_INFO(dev_priv)->gen == 2) {
+               if (IS_GEN2(dev_priv)) {
                        dev->driver->irq_preinstall = i8xx_irq_preinstall;
                        dev->driver->irq_postinstall = i8xx_irq_postinstall;
                        dev->driver->irq_handler = i8xx_irq_handler;
                        dev->driver->irq_uninstall = i8xx_irq_uninstall;
-               } else if (INTEL_INFO(dev_priv)->gen == 3) {
+               } else if (IS_GEN3(dev_priv)) {
                        dev->driver->irq_preinstall = i915_irq_preinstall;
                        dev->driver->irq_postinstall = i915_irq_postinstall;
                        dev->driver->irq_uninstall = i915_irq_uninstall;