Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / i915 / i915_irq.c
index 0b99de95593b5a6f650fe8b0aa3e487168d6af5f..267f069765adedffb942d1352649502ac624a364 100644 (file)
@@ -80,17 +80,64 @@ static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */
        [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
 };
 
+/* IIR can theoretically queue up two events. Be paranoid. */
+#define GEN8_IRQ_RESET_NDX(type, which) do { \
+       I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \
+       POSTING_READ(GEN8_##type##_IMR(which)); \
+       I915_WRITE(GEN8_##type##_IER(which), 0); \
+       I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \
+       POSTING_READ(GEN8_##type##_IIR(which)); \
+       I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \
+       POSTING_READ(GEN8_##type##_IIR(which)); \
+} while (0)
+
+#define GEN5_IRQ_RESET(type) do { \
+       I915_WRITE(type##IMR, 0xffffffff); \
+       POSTING_READ(type##IMR); \
+       I915_WRITE(type##IER, 0); \
+       I915_WRITE(type##IIR, 0xffffffff); \
+       POSTING_READ(type##IIR); \
+       I915_WRITE(type##IIR, 0xffffffff); \
+       POSTING_READ(type##IIR); \
+} while (0)
+
+/*
+ * We should clear IMR at preinstall/uninstall, and just check at postinstall.
+ */
+#define GEN5_ASSERT_IIR_IS_ZERO(reg) do { \
+       u32 val = I915_READ(reg); \
+       if (val) { \
+               WARN(1, "Interrupt register 0x%x is not zero: 0x%08x\n", \
+                    (reg), val); \
+               I915_WRITE((reg), 0xffffffff); \
+               POSTING_READ(reg); \
+               I915_WRITE((reg), 0xffffffff); \
+               POSTING_READ(reg); \
+       } \
+} while (0)
+
+#define GEN8_IRQ_INIT_NDX(type, which, imr_val, ier_val) do { \
+       GEN5_ASSERT_IIR_IS_ZERO(GEN8_##type##_IIR(which)); \
+       I915_WRITE(GEN8_##type##_IMR(which), (imr_val)); \
+       I915_WRITE(GEN8_##type##_IER(which), (ier_val)); \
+       POSTING_READ(GEN8_##type##_IER(which)); \
+} while (0)
+
+#define GEN5_IRQ_INIT(type, imr_val, ier_val) do { \
+       GEN5_ASSERT_IIR_IS_ZERO(type##IIR); \
+       I915_WRITE(type##IMR, (imr_val)); \
+       I915_WRITE(type##IER, (ier_val)); \
+       POSTING_READ(type##IER); \
+} while (0)
+
 /* For display hotplug interrupt */
 static void
 ironlake_enable_display_irq(struct drm_i915_private *dev_priv, u32 mask)
 {
        assert_spin_locked(&dev_priv->irq_lock);
 
-       if (dev_priv->pm.irqs_disabled) {
-               WARN(1, "IRQs disabled\n");
-               dev_priv->pm.regsave.deimr &= ~mask;
+       if (WARN_ON(dev_priv->pm.irqs_disabled))
                return;
-       }
 
        if ((dev_priv->irq_mask & mask) != 0) {
                dev_priv->irq_mask &= ~mask;
@@ -104,11 +151,8 @@ ironlake_disable_display_irq(struct drm_i915_private *dev_priv, u32 mask)
 {
        assert_spin_locked(&dev_priv->irq_lock);
 
-       if (dev_priv->pm.irqs_disabled) {
-               WARN(1, "IRQs disabled\n");
-               dev_priv->pm.regsave.deimr |= mask;
+       if (WARN_ON(dev_priv->pm.irqs_disabled))
                return;
-       }
 
        if ((dev_priv->irq_mask & mask) != mask) {
                dev_priv->irq_mask |= mask;
@@ -129,13 +173,8 @@ static void ilk_update_gt_irq(struct drm_i915_private *dev_priv,
 {
        assert_spin_locked(&dev_priv->irq_lock);
 
-       if (dev_priv->pm.irqs_disabled) {
-               WARN(1, "IRQs disabled\n");
-               dev_priv->pm.regsave.gtimr &= ~interrupt_mask;
-               dev_priv->pm.regsave.gtimr |= (~enabled_irq_mask &
-                                               interrupt_mask);
+       if (WARN_ON(dev_priv->pm.irqs_disabled))
                return;
-       }
 
        dev_priv->gt_irq_mask &= ~interrupt_mask;
        dev_priv->gt_irq_mask |= (~enabled_irq_mask & interrupt_mask);
@@ -167,13 +206,8 @@ static void snb_update_pm_irq(struct drm_i915_private *dev_priv,
 
        assert_spin_locked(&dev_priv->irq_lock);
 
-       if (dev_priv->pm.irqs_disabled) {
-               WARN(1, "IRQs disabled\n");
-               dev_priv->pm.regsave.gen6_pmimr &= ~interrupt_mask;
-               dev_priv->pm.regsave.gen6_pmimr |= (~enabled_irq_mask &
-                                                    interrupt_mask);
+       if (WARN_ON(dev_priv->pm.irqs_disabled))
                return;
-       }
 
        new_val = dev_priv->pm_irq_mask;
        new_val &= ~interrupt_mask;
@@ -214,6 +248,46 @@ static bool ivb_can_enable_err_int(struct drm_device *dev)
        return true;
 }
 
+/**
+  * bdw_update_pm_irq - update GT interrupt 2
+  * @dev_priv: driver private
+  * @interrupt_mask: mask of interrupt bits to update
+  * @enabled_irq_mask: mask of interrupt bits to enable
+  *
+  * Copied from the snb function, updated with relevant register offsets
+  */
+static void bdw_update_pm_irq(struct drm_i915_private *dev_priv,
+                             uint32_t interrupt_mask,
+                             uint32_t enabled_irq_mask)
+{
+       uint32_t new_val;
+
+       assert_spin_locked(&dev_priv->irq_lock);
+
+       if (WARN_ON(dev_priv->pm.irqs_disabled))
+               return;
+
+       new_val = dev_priv->pm_irq_mask;
+       new_val &= ~interrupt_mask;
+       new_val |= (~enabled_irq_mask & interrupt_mask);
+
+       if (new_val != dev_priv->pm_irq_mask) {
+               dev_priv->pm_irq_mask = new_val;
+               I915_WRITE(GEN8_GT_IMR(2), dev_priv->pm_irq_mask);
+               POSTING_READ(GEN8_GT_IMR(2));
+       }
+}
+
+void bdw_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
+{
+       bdw_update_pm_irq(dev_priv, mask, mask);
+}
+
+void bdw_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
+{
+       bdw_update_pm_irq(dev_priv, mask, 0);
+}
+
 static bool cpt_can_enable_serr_int(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -232,16 +306,51 @@ static bool cpt_can_enable_serr_int(struct drm_device *dev)
        return true;
 }
 
-static void i9xx_clear_fifo_underrun(struct drm_device *dev, enum pipe pipe)
+void i9xx_check_fifo_underruns(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *crtc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev_priv->irq_lock, flags);
+
+       for_each_intel_crtc(dev, crtc) {
+               u32 reg = PIPESTAT(crtc->pipe);
+               u32 pipestat;
+
+               if (crtc->cpu_fifo_underrun_disabled)
+                       continue;
+
+               pipestat = I915_READ(reg) & 0xffff0000;
+               if ((pipestat & PIPE_FIFO_UNDERRUN_STATUS) == 0)
+                       continue;
+
+               I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
+               POSTING_READ(reg);
+
+               DRM_ERROR("pipe %c underrun\n", pipe_name(crtc->pipe));
+       }
+
+       spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+}
+
+static void i9xx_set_fifo_underrun_reporting(struct drm_device *dev,
+                                            enum pipe pipe,
+                                            bool enable, bool old)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 reg = PIPESTAT(pipe);
-       u32 pipestat = I915_READ(reg) & 0x7fff0000;
+       u32 pipestat = I915_READ(reg) & 0xffff0000;
 
        assert_spin_locked(&dev_priv->irq_lock);
 
-       I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
-       POSTING_READ(reg);
+       if (enable) {
+               I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
+               POSTING_READ(reg);
+       } else {
+               if (old && pipestat & PIPE_FIFO_UNDERRUN_STATUS)
+                       DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
+       }
 }
 
 static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev,
@@ -258,7 +367,8 @@ static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev,
 }
 
 static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev,
-                                                 enum pipe pipe, bool enable)
+                                                 enum pipe pipe,
+                                                 bool enable, bool old)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        if (enable) {
@@ -269,15 +379,12 @@ static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev,
 
                ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
        } else {
-               bool was_enabled = !(I915_READ(DEIMR) & DE_ERR_INT_IVB);
-
-               /* Change the state _after_ we've read out the current one. */
                ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
 
-               if (!was_enabled &&
-                   (I915_READ(GEN7_ERR_INT) & ERR_INT_FIFO_UNDERRUN(pipe))) {
-                       DRM_DEBUG_KMS("uncleared fifo underrun on pipe %c\n",
-                                     pipe_name(pipe));
+               if (old &&
+                   I915_READ(GEN7_ERR_INT) & ERR_INT_FIFO_UNDERRUN(pipe)) {
+                       DRM_ERROR("uncleared fifo underrun on pipe %c\n",
+                                 pipe_name(pipe));
                }
        }
 }
@@ -313,14 +420,8 @@ static void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
 
        assert_spin_locked(&dev_priv->irq_lock);
 
-       if (dev_priv->pm.irqs_disabled &&
-           (interrupt_mask & SDE_HOTPLUG_MASK_CPT)) {
-               WARN(1, "IRQs disabled\n");
-               dev_priv->pm.regsave.sdeimr &= ~interrupt_mask;
-               dev_priv->pm.regsave.sdeimr |= (~enabled_irq_mask &
-                                                interrupt_mask);
+       if (WARN_ON(dev_priv->pm.irqs_disabled))
                return;
-       }
 
        I915_WRITE(SDEIMR, sdeimr);
        POSTING_READ(SDEIMR);
@@ -346,7 +447,7 @@ static void ibx_set_fifo_underrun_reporting(struct drm_device *dev,
 
 static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
                                            enum transcoder pch_transcoder,
-                                           bool enable)
+                                           bool enable, bool old)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
@@ -359,16 +460,12 @@ static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
 
                ibx_enable_display_interrupt(dev_priv, SDE_ERROR_CPT);
        } else {
-               uint32_t tmp = I915_READ(SERR_INT);
-               bool was_enabled = !(I915_READ(SDEIMR) & SDE_ERROR_CPT);
-
-               /* Change the state _after_ we've read out the current one. */
                ibx_disable_display_interrupt(dev_priv, SDE_ERROR_CPT);
 
-               if (!was_enabled &&
-                   (tmp & SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder))) {
-                       DRM_DEBUG_KMS("uncleared pch fifo underrun on pch transcoder %c\n",
-                                     transcoder_name(pch_transcoder));
+               if (old && I915_READ(SERR_INT) &
+                   SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder)) {
+                       DRM_ERROR("uncleared pch fifo underrun on pch transcoder %c\n",
+                                 transcoder_name(pch_transcoder));
                }
        }
 }
@@ -387,34 +484,29 @@ static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
  *
  * Returns the previous state of underrun reporting.
  */
-bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
-                                            enum pipe pipe, bool enable)
+static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
+                                                   enum pipe pipe, bool enable)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       bool ret;
+       bool old;
 
        assert_spin_locked(&dev_priv->irq_lock);
 
-       ret = !intel_crtc->cpu_fifo_underrun_disabled;
-
-       if (enable == ret)
-               goto done;
-
+       old = !intel_crtc->cpu_fifo_underrun_disabled;
        intel_crtc->cpu_fifo_underrun_disabled = !enable;
 
-       if (enable && (INTEL_INFO(dev)->gen < 5 || IS_VALLEYVIEW(dev)))
-               i9xx_clear_fifo_underrun(dev, pipe);
+       if (INTEL_INFO(dev)->gen < 5 || IS_VALLEYVIEW(dev))
+               i9xx_set_fifo_underrun_reporting(dev, pipe, enable, old);
        else if (IS_GEN5(dev) || IS_GEN6(dev))
                ironlake_set_fifo_underrun_reporting(dev, pipe, enable);
        else if (IS_GEN7(dev))
-               ivybridge_set_fifo_underrun_reporting(dev, pipe, enable);
+               ivybridge_set_fifo_underrun_reporting(dev, pipe, enable, old);
        else if (IS_GEN8(dev))
                broadwell_set_fifo_underrun_reporting(dev, pipe, enable);
 
-done:
-       return ret;
+       return old;
 }
 
 bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
@@ -463,7 +555,7 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
        struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder];
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        unsigned long flags;
-       bool ret;
+       bool old;
 
        /*
         * NOTE: Pre-LPT has a fixed cpu pipe -> pch transcoder mapping, but LPT
@@ -476,21 +568,16 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
 
-       ret = !intel_crtc->pch_fifo_underrun_disabled;
-
-       if (enable == ret)
-               goto done;
-
+       old = !intel_crtc->pch_fifo_underrun_disabled;
        intel_crtc->pch_fifo_underrun_disabled = !enable;
 
        if (HAS_PCH_IBX(dev))
                ibx_set_fifo_underrun_reporting(dev, pch_transcoder, enable);
        else
-               cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable);
+               cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable, old);
 
-done:
        spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
-       return ret;
+       return old;
 }
 
 
@@ -503,8 +590,10 @@ __i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
 
        assert_spin_locked(&dev_priv->irq_lock);
 
-       if (WARN_ON_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK ||
-                        status_mask & ~PIPESTAT_INT_STATUS_MASK))
+       if (WARN_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK ||
+                     status_mask & ~PIPESTAT_INT_STATUS_MASK,
+                     "pipe %c: enable_mask=0x%x, status_mask=0x%x\n",
+                     pipe_name(pipe), enable_mask, status_mask))
                return;
 
        if ((pipestat & enable_mask) == enable_mask)
@@ -527,8 +616,10 @@ __i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
 
        assert_spin_locked(&dev_priv->irq_lock);
 
-       if (WARN_ON_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK ||
-                        status_mask & ~PIPESTAT_INT_STATUS_MASK))
+       if (WARN_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK ||
+                     status_mask & ~PIPESTAT_INT_STATUS_MASK,
+                     "pipe %c: enable_mask=0x%x, status_mask=0x%x\n",
+                     pipe_name(pipe), enable_mask, status_mask))
                return;
 
        if ((pipestat & enable_mask) == 0)
@@ -546,11 +637,17 @@ static u32 vlv_get_pipestat_enable_mask(struct drm_device *dev, u32 status_mask)
        u32 enable_mask = status_mask << 16;
 
        /*
-        * On pipe A we don't support the PSR interrupt yet, on pipe B the
-        * same bit MBZ.
+        * On pipe A we don't support the PSR interrupt yet,
+        * on pipe B and C the same bit MBZ.
         */
        if (WARN_ON_ONCE(status_mask & PIPE_A_PSR_STATUS_VLV))
                return 0;
+       /*
+        * On pipe B and C we don't support the PSR interrupt yet, on pipe
+        * A the same bit is for perf counters which we don't use either.
+        */
+       if (WARN_ON_ONCE(status_mask & PIPE_B_PSR_STATUS_VLV))
+               return 0;
 
        enable_mask &= ~(PIPE_FIFO_UNDERRUN_STATUS |
                         SPRITE0_FLIP_DONE_INT_EN_VLV |
@@ -637,6 +734,56 @@ i915_pipe_enabled(struct drm_device *dev, int pipe)
        }
 }
 
+/*
+ * This timing diagram depicts the video signal in and
+ * around the vertical blanking period.
+ *
+ * Assumptions about the fictitious mode used in this example:
+ *  vblank_start >= 3
+ *  vsync_start = vblank_start + 1
+ *  vsync_end = vblank_start + 2
+ *  vtotal = vblank_start + 3
+ *
+ *           start of vblank:
+ *           latch double buffered registers
+ *           increment frame counter (ctg+)
+ *           generate start of vblank interrupt (gen4+)
+ *           |
+ *           |          frame start:
+ *           |          generate frame start interrupt (aka. vblank interrupt) (gmch)
+ *           |          may be shifted forward 1-3 extra lines via PIPECONF
+ *           |          |
+ *           |          |  start of vsync:
+ *           |          |  generate vsync interrupt
+ *           |          |  |
+ * ___xxxx___    ___xxxx___    ___xxxx___    ___xxxx___    ___xxxx___    ___xxxx
+ *       .   \hs/   .      \hs/          \hs/          \hs/   .      \hs/
+ * ----va---> <-----------------vb--------------------> <--------va-------------
+ *       |          |       <----vs----->                     |
+ * -vbs-----> <---vbs+1---> <---vbs+2---> <-----0-----> <-----1-----> <-----2--- (scanline counter gen2)
+ * -vbs-2---> <---vbs-1---> <---vbs-----> <---vbs+1---> <---vbs+2---> <-----0--- (scanline counter gen3+)
+ * -vbs-2---> <---vbs-2---> <---vbs-1---> <---vbs-----> <---vbs+1---> <---vbs+2- (scanline counter hsw+ hdmi)
+ *       |          |                                         |
+ *       last visible pixel                                   first visible pixel
+ *                  |                                         increment frame counter (gen3/4)
+ *                  pixel counter = vblank_start * htotal     pixel counter = 0 (gen3/4)
+ *
+ * x  = horizontal active
+ * _  = horizontal blanking
+ * hs = horizontal sync
+ * va = vertical active
+ * vb = vertical blanking
+ * vs = vertical sync
+ * vbs = vblank_start (number)
+ *
+ * Summary:
+ * - most events happen at the start of horizontal sync
+ * - frame start happens at the start of horizontal blank, 1-4 lines
+ *   (depending on PIPECONF settings) after the start of vblank
+ * - gen3/4 pixel and frame counter are synchronized with the start
+ *   of horizontal active on the first line of vertical active
+ */
+
 static u32 i8xx_get_vblank_counter(struct drm_device *dev, int pipe)
 {
        /* Gen2 doesn't have a hardware frame counter */
@@ -651,7 +798,7 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long high_frame;
        unsigned long low_frame;
-       u32 high1, high2, low, pixel, vbl_start;
+       u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal;
 
        if (!i915_pipe_enabled(dev, pipe)) {
                DRM_DEBUG_DRIVER("trying to get vblank count for disabled "
@@ -665,17 +812,28 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
                const struct drm_display_mode *mode =
                        &intel_crtc->config.adjusted_mode;
 
-               vbl_start = mode->crtc_vblank_start * mode->crtc_htotal;
+               htotal = mode->crtc_htotal;
+               hsync_start = mode->crtc_hsync_start;
+               vbl_start = mode->crtc_vblank_start;
+               if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+                       vbl_start = DIV_ROUND_UP(vbl_start, 2);
        } else {
                enum transcoder cpu_transcoder = (enum transcoder) pipe;
-               u32 htotal;
 
                htotal = ((I915_READ(HTOTAL(cpu_transcoder)) >> 16) & 0x1fff) + 1;
+               hsync_start = (I915_READ(HSYNC(cpu_transcoder))  & 0x1fff) + 1;
                vbl_start = (I915_READ(VBLANK(cpu_transcoder)) & 0x1fff) + 1;
-
-               vbl_start *= htotal;
+               if ((I915_READ(PIPECONF(cpu_transcoder)) &
+                    PIPECONF_INTERLACE_MASK) != PIPECONF_PROGRESSIVE)
+                       vbl_start = DIV_ROUND_UP(vbl_start, 2);
        }
 
+       /* Convert to pixel count */
+       vbl_start *= htotal;
+
+       /* Start of vblank event occurs at start of hsync */
+       vbl_start -= htotal - hsync_start;
+
        high_frame = PIPEFRAME(pipe);
        low_frame = PIPEFRAMEPIXEL(pipe);
 
@@ -719,24 +877,28 @@ static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
 /* raw reads, only for fast reads of display block, no need for forcewake etc. */
 #define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__))
 
-static bool ilk_pipe_in_vblank_locked(struct drm_device *dev, enum pipe pipe)
+static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
 {
+       struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t status;
-       int reg;
+       const struct drm_display_mode *mode = &crtc->config.adjusted_mode;
+       enum pipe pipe = crtc->pipe;
+       int position, vtotal;
 
-       if (INTEL_INFO(dev)->gen >= 8) {
-               status = GEN8_PIPE_VBLANK;
-               reg = GEN8_DE_PIPE_ISR(pipe);
-       } else if (INTEL_INFO(dev)->gen >= 7) {
-               status = DE_PIPE_VBLANK_IVB(pipe);
-               reg = DEISR;
-       } else {
-               status = DE_PIPE_VBLANK(pipe);
-               reg = DEISR;
-       }
+       vtotal = mode->crtc_vtotal;
+       if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+               vtotal /= 2;
 
-       return __raw_i915_read32(dev_priv, reg) & status;
+       if (IS_GEN2(dev))
+               position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN2;
+       else
+               position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
+
+       /*
+        * See update_scanline_offset() for the details on the
+        * scanline_offset adjustment.
+        */
+       return (position + crtc->scanline_offset) % vtotal;
 }
 
 static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
@@ -748,7 +910,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        const struct drm_display_mode *mode = &intel_crtc->config.adjusted_mode;
        int position;
-       int vbl_start, vbl_end, htotal, vtotal;
+       int vbl_start, vbl_end, hsync_start, htotal, vtotal;
        bool in_vbl = true;
        int ret = 0;
        unsigned long irqflags;
@@ -760,6 +922,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
        }
 
        htotal = mode->crtc_htotal;
+       hsync_start = mode->crtc_hsync_start;
        vtotal = mode->crtc_vtotal;
        vbl_start = mode->crtc_vblank_start;
        vbl_end = mode->crtc_vblank_end;
@@ -778,7 +941,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
         * following code must not block on uncore.lock.
         */
        spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
-       
+
        /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */
 
        /* Get optional system timestamp before query. */
@@ -789,68 +952,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
                /* No obvious pixelcount register. Only query vertical
                 * scanout position from Display scan line register.
                 */
-               if (IS_GEN2(dev))
-                       position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN2;
-               else
-                       position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
-
-               if (HAS_DDI(dev)) {
-                       /*
-                        * On HSW HDMI outputs there seems to be a 2 line
-                        * difference, whereas eDP has the normal 1 line
-                        * difference that earlier platforms have. External
-                        * DP is unknown. For now just check for the 2 line
-                        * difference case on all output types on HSW+.
-                        *
-                        * This might misinterpret the scanline counter being
-                        * one line too far along on eDP, but that's less
-                        * dangerous than the alternative since that would lead
-                        * the vblank timestamp code astray when it sees a
-                        * scanline count before vblank_start during a vblank
-                        * interrupt.
-                        */
-                       in_vbl = ilk_pipe_in_vblank_locked(dev, pipe);
-                       if ((in_vbl && (position == vbl_start - 2 ||
-                                       position == vbl_start - 1)) ||
-                           (!in_vbl && (position == vbl_end - 2 ||
-                                        position == vbl_end - 1)))
-                               position = (position + 2) % vtotal;
-               } else if (HAS_PCH_SPLIT(dev)) {
-                       /*
-                        * The scanline counter increments at the leading edge
-                        * of hsync, ie. it completely misses the active portion
-                        * of the line. Fix up the counter at both edges of vblank
-                        * to get a more accurate picture whether we're in vblank
-                        * or not.
-                        */
-                       in_vbl = ilk_pipe_in_vblank_locked(dev, pipe);
-                       if ((in_vbl && position == vbl_start - 1) ||
-                           (!in_vbl && position == vbl_end - 1))
-                               position = (position + 1) % vtotal;
-               } else {
-                       /*
-                        * ISR vblank status bits don't work the way we'd want
-                        * them to work on non-PCH platforms (for
-                        * ilk_pipe_in_vblank_locked()), and there doesn't
-                        * appear any other way to determine if we're currently
-                        * in vblank.
-                        *
-                        * Instead let's assume that we're already in vblank if
-                        * we got called from the vblank interrupt and the
-                        * scanline counter value indicates that we're on the
-                        * line just prior to vblank start. This should result
-                        * in the correct answer, unless the vblank interrupt
-                        * delivery really got delayed for almost exactly one
-                        * full frame/field.
-                        */
-                       if (flags & DRM_CALLED_FROM_VBLIRQ &&
-                           position == vbl_start - 1) {
-                               position = (position + 1) % vtotal;
-
-                               /* Signal this correction as "applied". */
-                               ret |= 0x8;
-                       }
-               }
+               position = __intel_get_crtc_scanline(intel_crtc);
        } else {
                /* Have access to pixelcount since start of frame.
                 * We can split this into vertical and horizontal
@@ -862,6 +964,29 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
                vbl_start *= htotal;
                vbl_end *= htotal;
                vtotal *= htotal;
+
+               /*
+                * In interlaced modes, the pixel counter counts all pixels,
+                * so one field will have htotal more pixels. In order to avoid
+                * the reported position from jumping backwards when the pixel
+                * counter is beyond the length of the shorter field, just
+                * clamp the position the length of the shorter field. This
+                * matches how the scanline counter based position works since
+                * the scanline counter doesn't count the two half lines.
+                */
+               if (position >= vtotal)
+                       position = vtotal - 1;
+
+               /*
+                * Start of vblank interrupt is triggered at start of hsync,
+                * just prior to the first active line of vblank. However we
+                * consider lines to start at the leading edge of horizontal
+                * active. So, should we get here before we've crossed into
+                * the horizontal active of the first line in vblank, we would
+                * not set the DRM_SCANOUTPOS_INVBL flag. In order to fix that,
+                * always add htotal-hsync_start to the current pixel position.
+                */
+               position = (position + htotal - hsync_start) % vtotal;
        }
 
        /* Get optional system timestamp after query. */
@@ -900,6 +1025,19 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
        return ret;
 }
 
+int intel_get_crtc_scanline(struct intel_crtc *crtc)
+{
+       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+       unsigned long irqflags;
+       int position;
+
+       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+       position = __intel_get_crtc_scanline(crtc);
+       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+
+       return position;
+}
+
 static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe,
                              int *max_error,
                              struct timeval *vblank_time,
@@ -945,7 +1083,7 @@ static bool intel_hpd_irq_event(struct drm_device *dev,
 
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n",
                      connector->base.id,
-                     drm_get_connector_name(connector),
+                     connector->name,
                      drm_get_connector_status_name(old_status),
                      drm_get_connector_status_name(connector->status));
 
@@ -990,7 +1128,7 @@ static void i915_hotplug_work_func(struct work_struct *work)
                    connector->polled == DRM_CONNECTOR_POLL_HPD) {
                        DRM_INFO("HPD interrupt storm detected on connector %s: "
                                 "switching from hotplug detection to polling\n",
-                               drm_get_connector_name(connector));
+                               connector->name);
                        dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark = HPD_DISABLED;
                        connector->polled = DRM_CONNECTOR_POLL_CONNECT
                                | DRM_CONNECTOR_POLL_DISCONNECT;
@@ -998,7 +1136,7 @@ static void i915_hotplug_work_func(struct work_struct *work)
                }
                if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) {
                        DRM_DEBUG_KMS("Connector %s (pin %i) received hotplug event.\n",
-                                     drm_get_connector_name(connector), intel_encoder->hpd_pin);
+                                     connector->name, intel_encoder->hpd_pin);
                }
        }
         /* if there were no outputs to poll, poll was disabled,
@@ -1073,9 +1211,9 @@ static void ironlake_rps_change_irq_handler(struct drm_device *dev)
 }
 
 static void notify_ring(struct drm_device *dev,
-                       struct intel_ring_buffer *ring)
+                       struct intel_engine_cs *ring)
 {
-       if (ring->obj == NULL)
+       if (!intel_ring_initialized(ring))
                return;
 
        trace_i915_gem_request_complete(ring);
@@ -1094,8 +1232,12 @@ static void gen6_pm_rps_work(struct work_struct *work)
        spin_lock_irq(&dev_priv->irq_lock);
        pm_iir = dev_priv->rps.pm_iir;
        dev_priv->rps.pm_iir = 0;
-       /* Make sure not to corrupt PMIMR state used by ringbuffer code */
-       snb_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
+       if (IS_BROADWELL(dev_priv->dev))
+               bdw_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
+       else {
+               /* Make sure not to corrupt PMIMR state used by ringbuffer */
+               snb_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
+       }
        spin_unlock_irq(&dev_priv->irq_lock);
 
        /* Make sure we didn't queue anything we're not going to process. */
@@ -1292,6 +1434,19 @@ static void snb_gt_irq_handler(struct drm_device *dev,
                ivybridge_parity_error_irq_handler(dev, gt_iir);
 }
 
+static void gen8_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
+{
+       if ((pm_iir & dev_priv->pm_rps_events) == 0)
+               return;
+
+       spin_lock(&dev_priv->irq_lock);
+       dev_priv->rps.pm_iir |= pm_iir & dev_priv->pm_rps_events;
+       bdw_disable_pm_irq(dev_priv, pm_iir & dev_priv->pm_rps_events);
+       spin_unlock(&dev_priv->irq_lock);
+
+       queue_work(dev_priv->wq, &dev_priv->rps.work);
+}
+
 static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
                                       struct drm_i915_private *dev_priv,
                                       u32 master_ctl)
@@ -1315,18 +1470,32 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
                        DRM_ERROR("The master control interrupt lied (GT0)!\n");
        }
 
-       if (master_ctl & GEN8_GT_VCS1_IRQ) {
+       if (master_ctl & (GEN8_GT_VCS1_IRQ | GEN8_GT_VCS2_IRQ)) {
                tmp = I915_READ(GEN8_GT_IIR(1));
                if (tmp) {
                        ret = IRQ_HANDLED;
                        vcs = tmp >> GEN8_VCS1_IRQ_SHIFT;
                        if (vcs & GT_RENDER_USER_INTERRUPT)
                                notify_ring(dev, &dev_priv->ring[VCS]);
+                       vcs = tmp >> GEN8_VCS2_IRQ_SHIFT;
+                       if (vcs & GT_RENDER_USER_INTERRUPT)
+                               notify_ring(dev, &dev_priv->ring[VCS2]);
                        I915_WRITE(GEN8_GT_IIR(1), tmp);
                } else
                        DRM_ERROR("The master control interrupt lied (GT1)!\n");
        }
 
+       if (master_ctl & GEN8_GT_PM_IRQ) {
+               tmp = I915_READ(GEN8_GT_IIR(2));
+               if (tmp & dev_priv->pm_rps_events) {
+                       ret = IRQ_HANDLED;
+                       gen8_rps_irq_handler(dev_priv, tmp);
+                       I915_WRITE(GEN8_GT_IIR(2),
+                                  tmp & dev_priv->pm_rps_events);
+               } else
+                       DRM_ERROR("The master control interrupt lied (PM)!\n");
+       }
+
        if (master_ctl & GEN8_GT_VECS_IRQ) {
                tmp = I915_READ(GEN8_GT_IIR(3));
                if (tmp) {
@@ -1549,6 +1718,19 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
        }
 }
 
+static bool intel_pipe_handle_vblank(struct drm_device *dev, enum pipe pipe)
+{
+       struct intel_crtc *crtc;
+
+       if (!drm_handle_vblank(dev, pipe))
+               return false;
+
+       crtc = to_intel_crtc(intel_get_crtc_for_pipe(dev, pipe));
+       wake_up(&crtc->vbl_wait);
+
+       return true;
+}
+
 static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1578,6 +1760,9 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
                case PIPE_B:
                        iir_bit = I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
                        break;
+               case PIPE_C:
+                       iir_bit = I915_DISPLAY_PIPE_C_EVENT_INTERRUPT;
+                       break;
                }
                if (iir & iir_bit)
                        mask |= dev_priv->pipestat_irq_mask[pipe];
@@ -1600,7 +1785,7 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
 
        for_each_pipe(pipe) {
                if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
-                       drm_handle_vblank(dev, pipe);
+                       intel_pipe_handle_vblank(dev, pipe);
 
                if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV) {
                        intel_prepare_page_flip(dev, pipe);
@@ -1619,9 +1804,36 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
                gmbus_irq_handler(dev);
 }
 
+static void i9xx_hpd_irq_handler(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
+
+       if (IS_G4X(dev)) {
+               u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X;
+
+               intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_g4x);
+       } else {
+               u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
+
+               intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
+       }
+
+       if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)) &&
+           hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X)
+               dp_aux_irq_handler(dev);
+
+       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);
+}
+
 static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 {
-       struct drm_device *dev = (struct drm_device *) 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;
@@ -1641,19 +1853,8 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
                valleyview_pipestat_irq_handler(dev, iir);
 
                /* Consume port.  Then clear IIR or we'll miss events */
-               if (iir & I915_DISPLAY_PORT_INTERRUPT) {
-                       u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
-                       u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
-
-                       intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
-
-                       if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X)
-                               dp_aux_irq_handler(dev);
-
-                       I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
-                       I915_READ(PORT_HOTPLUG_STAT);
-               }
-
+               if (iir & I915_DISPLAY_PORT_INTERRUPT)
+                       i9xx_hpd_irq_handler(dev);
 
                if (pm_iir)
                        gen6_rps_irq_handler(dev_priv, pm_iir);
@@ -1667,6 +1868,40 @@ out:
        return ret;
 }
 
+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;
+
+       for (;;) {
+               master_ctl = I915_READ(GEN8_MASTER_IRQ) & ~GEN8_MASTER_IRQ_CONTROL;
+               iir = I915_READ(VLV_IIR);
+
+               if (master_ctl == 0 && iir == 0)
+                       break;
+
+               I915_WRITE(GEN8_MASTER_IRQ, 0);
+
+               gen8_gt_irq_handler(dev, dev_priv, master_ctl);
+
+               valleyview_pipestat_irq_handler(dev, iir);
+
+               /* Consume port.  Then clear IIR or we'll miss events */
+               i9xx_hpd_irq_handler(dev);
+
+               I915_WRITE(VLV_IIR, iir);
+
+               I915_WRITE(GEN8_MASTER_IRQ, DE_MASTER_IRQ_CONTROL);
+               POSTING_READ(GEN8_MASTER_IRQ);
+
+               ret = IRQ_HANDLED;
+       }
+
+       return ret;
+}
+
 static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1827,7 +2062,7 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
 
        for_each_pipe(pipe) {
                if (de_iir & DE_PIPE_VBLANK(pipe))
-                       drm_handle_vblank(dev, pipe);
+                       intel_pipe_handle_vblank(dev, pipe);
 
                if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe))
                        if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
@@ -1877,7 +2112,7 @@ static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
 
        for_each_pipe(pipe) {
                if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)))
-                       drm_handle_vblank(dev, pipe);
+                       intel_pipe_handle_vblank(dev, pipe);
 
                /* plane/pipes map 1:1 on ilk+ */
                if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) {
@@ -1899,7 +2134,7 @@ static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
 
 static irqreturn_t ironlake_irq_handler(int irq, void *arg)
 {
-       struct drm_device *dev = (struct drm_device *) arg;
+       struct drm_device *dev = arg;
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 de_iir, gt_iir, de_ier, sde_ier = 0;
        irqreturn_t ret = IRQ_NONE;
@@ -2020,9 +2255,9 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
 
                pipe_iir = I915_READ(GEN8_DE_PIPE_IIR(pipe));
                if (pipe_iir & GEN8_PIPE_VBLANK)
-                       drm_handle_vblank(dev, pipe);
+                       intel_pipe_handle_vblank(dev, pipe);
 
-               if (pipe_iir & GEN8_PIPE_FLIP_DONE) {
+               if (pipe_iir & GEN8_PIPE_PRIMARY_FLIP_DONE) {
                        intel_prepare_page_flip(dev, pipe);
                        intel_finish_page_flip_plane(dev, pipe);
                }
@@ -2075,7 +2310,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_ring_buffer *ring;
+       struct intel_engine_cs *ring;
        int i;
 
        /*
@@ -2136,6 +2371,14 @@ static void i915_error_work_func(struct work_struct *work)
                kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE,
                                   reset_event);
 
+               /*
+                * In most cases it's guaranteed that we get here with an RPM
+                * reference held, for example because there is a pending GPU
+                * request that won't finish until the reset is done. This
+                * isn't the case at least when we get here by doing a
+                * simulated reset via debugs, so get an RPM reference.
+                */
+               intel_runtime_pm_get(dev_priv);
                /*
                 * All state reset _must_ be completed before we update the
                 * reset counter, for otherwise waiters might miss the reset
@@ -2146,6 +2389,8 @@ static void i915_error_work_func(struct work_struct *work)
 
                intel_display_handle_reset(dev);
 
+               intel_runtime_pm_put(dev_priv);
+
                if (ret == 0) {
                        /*
                         * After all the gem state is reset, increment the reset
@@ -2383,10 +2628,6 @@ static int i915_enable_vblank(struct drm_device *dev, int pipe)
        else
                i915_enable_pipestat(dev_priv, pipe,
                                     PIPE_VBLANK_INTERRUPT_STATUS);
-
-       /* maintain vblank delivery even in deep C-states */
-       if (INTEL_INFO(dev)->gen == 3)
-               I915_WRITE(INSTPM, _MASKED_BIT_DISABLE(INSTPM_AGPBUSY_DIS));
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
        return 0;
@@ -2450,9 +2691,6 @@ static void i915_disable_vblank(struct drm_device *dev, int pipe)
        unsigned long irqflags;
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       if (INTEL_INFO(dev)->gen == 3)
-               I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_AGPBUSY_DIS));
-
        i915_disable_pipestat(dev_priv, pipe,
                              PIPE_VBLANK_INTERRUPT_STATUS |
                              PIPE_START_VBLANK_INTERRUPT_STATUS);
@@ -2498,29 +2736,77 @@ static void gen8_disable_vblank(struct drm_device *dev, int pipe)
 }
 
 static u32
-ring_last_seqno(struct intel_ring_buffer *ring)
+ring_last_seqno(struct intel_engine_cs *ring)
 {
        return list_entry(ring->request_list.prev,
                          struct drm_i915_gem_request, list)->seqno;
 }
 
 static bool
-ring_idle(struct intel_ring_buffer *ring, u32 seqno)
+ring_idle(struct intel_engine_cs *ring, u32 seqno)
 {
        return (list_empty(&ring->request_list) ||
                i915_seqno_passed(seqno, ring_last_seqno(ring)));
 }
 
-static struct intel_ring_buffer *
-semaphore_waits_for(struct intel_ring_buffer *ring, u32 *seqno)
+static bool
+ipehr_is_semaphore_wait(struct drm_device *dev, u32 ipehr)
+{
+       if (INTEL_INFO(dev)->gen >= 8) {
+               /*
+                * FIXME: gen8 semaphore support - currently we don't emit
+                * semaphores on bdw anyway, but this needs to be addressed when
+                * we merge that code.
+                */
+               return false;
+       } else {
+               ipehr &= ~MI_SEMAPHORE_SYNC_MASK;
+               return ipehr == (MI_SEMAPHORE_MBOX | MI_SEMAPHORE_COMPARE |
+                                MI_SEMAPHORE_REGISTER);
+       }
+}
+
+static struct intel_engine_cs *
+semaphore_wait_to_signaller_ring(struct intel_engine_cs *ring, u32 ipehr)
+{
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       struct intel_engine_cs *signaller;
+       int i;
+
+       if (INTEL_INFO(dev_priv->dev)->gen >= 8) {
+               /*
+                * FIXME: gen8 semaphore support - currently we don't emit
+                * semaphores on bdw anyway, but this needs to be addressed when
+                * we merge that code.
+                */
+               return NULL;
+       } else {
+               u32 sync_bits = ipehr & MI_SEMAPHORE_SYNC_MASK;
+
+               for_each_ring(signaller, dev_priv, i) {
+                       if(ring == signaller)
+                               continue;
+
+                       if (sync_bits == signaller->semaphore.mbox.wait[ring->id])
+                               return signaller;
+               }
+       }
+
+       DRM_ERROR("No signaller ring found for ring %i, ipehr 0x%08x\n",
+                 ring->id, ipehr);
+
+       return NULL;
+}
+
+static struct intel_engine_cs *
+semaphore_waits_for(struct intel_engine_cs *ring, u32 *seqno)
 {
        struct drm_i915_private *dev_priv = ring->dev->dev_private;
        u32 cmd, ipehr, head;
        int i;
 
        ipehr = I915_READ(RING_IPEHR(ring->mmio_base));
-       if ((ipehr & ~(0x3 << 16)) !=
-           (MI_SEMAPHORE_MBOX | MI_SEMAPHORE_COMPARE | MI_SEMAPHORE_REGISTER))
+       if (!ipehr_is_semaphore_wait(ring->dev, ipehr))
                return NULL;
 
        /*
@@ -2538,10 +2824,10 @@ semaphore_waits_for(struct intel_ring_buffer *ring, u32 *seqno)
                 * our ring is smaller than what the hardware (and hence
                 * HEAD_ADDR) allows. Also handles wrap-around.
                 */
-               head &= ring->size - 1;
+               head &= ring->buffer->size - 1;
 
                /* This here seems to blow up */
-               cmd = ioread32(ring->virtual_start + head);
+               cmd = ioread32(ring->buffer->virtual_start + head);
                if (cmd == ipehr)
                        break;
 
@@ -2551,20 +2837,24 @@ semaphore_waits_for(struct intel_ring_buffer *ring, u32 *seqno)
        if (!i)
                return NULL;
 
-       *seqno = ioread32(ring->virtual_start + head + 4) + 1;
-       return &dev_priv->ring[(ring->id + (((ipehr >> 17) & 1) + 1)) % 3];
+       *seqno = ioread32(ring->buffer->virtual_start + head + 4) + 1;
+       return semaphore_wait_to_signaller_ring(ring, ipehr);
 }
 
-static int semaphore_passed(struct intel_ring_buffer *ring)
+static int semaphore_passed(struct intel_engine_cs *ring)
 {
        struct drm_i915_private *dev_priv = ring->dev->dev_private;
-       struct intel_ring_buffer *signaller;
+       struct intel_engine_cs *signaller;
        u32 seqno, ctl;
 
-       ring->hangcheck.deadlock = true;
+       ring->hangcheck.deadlock++;
 
        signaller = semaphore_waits_for(ring, &seqno);
-       if (signaller == NULL || signaller->hangcheck.deadlock)
+       if (signaller == NULL)
+               return -1;
+
+       /* Prevent pathological recursion due to driver bugs */
+       if (signaller->hangcheck.deadlock >= I915_NUM_RINGS)
                return -1;
 
        /* cursory check for an unkickable deadlock */
@@ -2572,20 +2862,26 @@ static int semaphore_passed(struct intel_ring_buffer *ring)
        if (ctl & RING_WAIT_SEMAPHORE && semaphore_passed(signaller) < 0)
                return -1;
 
-       return i915_seqno_passed(signaller->get_seqno(signaller, false), seqno);
+       if (i915_seqno_passed(signaller->get_seqno(signaller, false), seqno))
+               return 1;
+
+       if (signaller->hangcheck.deadlock)
+               return -1;
+
+       return 0;
 }
 
 static void semaphore_clear_deadlocks(struct drm_i915_private *dev_priv)
 {
-       struct intel_ring_buffer *ring;
+       struct intel_engine_cs *ring;
        int i;
 
        for_each_ring(ring, dev_priv, i)
-               ring->hangcheck.deadlock = false;
+               ring->hangcheck.deadlock = 0;
 }
 
 static enum intel_ring_hangcheck_action
-ring_stuck(struct intel_ring_buffer *ring, u64 acthd)
+ring_stuck(struct intel_engine_cs *ring, u64 acthd)
 {
        struct drm_device *dev = ring->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2641,7 +2937,7 @@ static void i915_hangcheck_elapsed(unsigned long data)
 {
        struct drm_device *dev = (struct drm_device *)data;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_ring_buffer *ring;
+       struct intel_engine_cs *ring;
        int i;
        int busy_count = 0, rings_hung = 0;
        bool stuck[I915_NUM_RINGS] = { 0 };
@@ -2759,57 +3055,63 @@ void i915_queue_hangcheck(struct drm_device *dev)
                  round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES));
 }
 
-static void ibx_irq_preinstall(struct drm_device *dev)
+static void ibx_irq_reset(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        if (HAS_PCH_NOP(dev))
                return;
 
-       /* south display irq */
-       I915_WRITE(SDEIMR, 0xffffffff);
-       /*
-        * SDEIER is also touched by the interrupt handler to work around missed
-        * PCH interrupts. Hence we can't update it after the interrupt handler
-        * is enabled - instead we unconditionally enable all PCH interrupt
-        * sources here, but then only unmask them as needed with SDEIMR.
-        */
+       GEN5_IRQ_RESET(SDE);
+
+       if (HAS_PCH_CPT(dev) || HAS_PCH_LPT(dev))
+               I915_WRITE(SERR_INT, 0xffffffff);
+}
+
+/*
+ * SDEIER is also touched by the interrupt handler to work around missed PCH
+ * interrupts. Hence we can't update it after the interrupt handler is enabled -
+ * instead we unconditionally enable all PCH interrupt sources here, but then
+ * only unmask them as needed with SDEIMR.
+ *
+ * This function needs to be called before interrupts are enabled.
+ */
+static void ibx_irq_pre_postinstall(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (HAS_PCH_NOP(dev))
+               return;
+
+       WARN_ON(I915_READ(SDEIER) != 0);
        I915_WRITE(SDEIER, 0xffffffff);
        POSTING_READ(SDEIER);
 }
 
-static void gen5_gt_irq_preinstall(struct drm_device *dev)
+static void gen5_gt_irq_reset(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       /* and GT */
-       I915_WRITE(GTIMR, 0xffffffff);
-       I915_WRITE(GTIER, 0x0);
-       POSTING_READ(GTIER);
-
-       if (INTEL_INFO(dev)->gen >= 6) {
-               /* and PM */
-               I915_WRITE(GEN6_PMIMR, 0xffffffff);
-               I915_WRITE(GEN6_PMIER, 0x0);
-               POSTING_READ(GEN6_PMIER);
-       }
+       GEN5_IRQ_RESET(GT);
+       if (INTEL_INFO(dev)->gen >= 6)
+               GEN5_IRQ_RESET(GEN6_PM);
 }
 
 /* drm_dma.h hooks
 */
-static void ironlake_irq_preinstall(struct drm_device *dev)
+static void ironlake_irq_reset(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       I915_WRITE(HWSTAM, 0xeffe);
+       I915_WRITE(HWSTAM, 0xffffffff);
 
-       I915_WRITE(DEIMR, 0xffffffff);
-       I915_WRITE(DEIER, 0x0);
-       POSTING_READ(DEIER);
+       GEN5_IRQ_RESET(DE);
+       if (IS_GEN7(dev))
+               I915_WRITE(GEN7_ERR_INT, 0xffffffff);
 
-       gen5_gt_irq_preinstall(dev);
+       gen5_gt_irq_reset(dev);
 
-       ibx_irq_preinstall(dev);
+       ibx_irq_reset(dev);
 }
 
 static void valleyview_irq_preinstall(struct drm_device *dev)
@@ -2827,7 +3129,7 @@ static void valleyview_irq_preinstall(struct drm_device *dev)
        I915_WRITE(GTIIR, I915_READ(GTIIR));
        I915_WRITE(GTIIR, I915_READ(GTIIR));
 
-       gen5_gt_irq_preinstall(dev);
+       gen5_gt_irq_reset(dev);
 
        I915_WRITE(DPINVGTT, 0xff);
 
@@ -2841,7 +3143,15 @@ static void valleyview_irq_preinstall(struct drm_device *dev)
        POSTING_READ(VLV_IER);
 }
 
-static void gen8_irq_preinstall(struct drm_device *dev)
+static void gen8_gt_irq_reset(struct drm_i915_private *dev_priv)
+{
+       GEN8_IRQ_RESET_NDX(GT, 0);
+       GEN8_IRQ_RESET_NDX(GT, 1);
+       GEN8_IRQ_RESET_NDX(GT, 2);
+       GEN8_IRQ_RESET_NDX(GT, 3);
+}
+
+static void gen8_irq_reset(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe;
@@ -2849,43 +3159,44 @@ static void gen8_irq_preinstall(struct drm_device *dev)
        I915_WRITE(GEN8_MASTER_IRQ, 0);
        POSTING_READ(GEN8_MASTER_IRQ);
 
-       /* IIR can theoretically queue up two events. Be paranoid */
-#define GEN8_IRQ_INIT_NDX(type, which) do { \
-               I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \
-               POSTING_READ(GEN8_##type##_IMR(which)); \
-               I915_WRITE(GEN8_##type##_IER(which), 0); \
-               I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \
-               POSTING_READ(GEN8_##type##_IIR(which)); \
-               I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \
-       } while (0)
-
-#define GEN8_IRQ_INIT(type) do { \
-               I915_WRITE(GEN8_##type##_IMR, 0xffffffff); \
-               POSTING_READ(GEN8_##type##_IMR); \
-               I915_WRITE(GEN8_##type##_IER, 0); \
-               I915_WRITE(GEN8_##type##_IIR, 0xffffffff); \
-               POSTING_READ(GEN8_##type##_IIR); \
-               I915_WRITE(GEN8_##type##_IIR, 0xffffffff); \
-       } while (0)
-
-       GEN8_IRQ_INIT_NDX(GT, 0);
-       GEN8_IRQ_INIT_NDX(GT, 1);
-       GEN8_IRQ_INIT_NDX(GT, 2);
-       GEN8_IRQ_INIT_NDX(GT, 3);
+       gen8_gt_irq_reset(dev_priv);
 
-       for_each_pipe(pipe) {
-               GEN8_IRQ_INIT_NDX(DE_PIPE, pipe);
-       }
+       for_each_pipe(pipe)
+               GEN8_IRQ_RESET_NDX(DE_PIPE, pipe);
+
+       GEN5_IRQ_RESET(GEN8_DE_PORT_);
+       GEN5_IRQ_RESET(GEN8_DE_MISC_);
+       GEN5_IRQ_RESET(GEN8_PCU_);
+
+       ibx_irq_reset(dev);
+}
+
+static void cherryview_irq_preinstall(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int pipe;
+
+       I915_WRITE(GEN8_MASTER_IRQ, 0);
+       POSTING_READ(GEN8_MASTER_IRQ);
 
-       GEN8_IRQ_INIT(DE_PORT);
-       GEN8_IRQ_INIT(DE_MISC);
-       GEN8_IRQ_INIT(PCU);
-#undef GEN8_IRQ_INIT
-#undef GEN8_IRQ_INIT_NDX
+       gen8_gt_irq_reset(dev_priv);
+
+       GEN5_IRQ_RESET(GEN8_PCU_);
 
        POSTING_READ(GEN8_PCU_IIR);
 
-       ibx_irq_preinstall(dev);
+       I915_WRITE(DPINVGTT, DPINVGTT_STATUS_MASK_CHV);
+
+       I915_WRITE(PORT_HOTPLUG_EN, 0);
+       I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
+
+       for_each_pipe(pipe)
+               I915_WRITE(PIPESTAT(pipe), 0xffff);
+
+       I915_WRITE(VLV_IMR, 0xffffffff);
+       I915_WRITE(VLV_IER, 0x0);
+       I915_WRITE(VLV_IIR, 0xffffffff);
+       POSTING_READ(VLV_IIR);
 }
 
 static void ibx_hpd_irq_setup(struct drm_device *dev)
@@ -2931,15 +3242,12 @@ static void ibx_irq_postinstall(struct drm_device *dev)
        if (HAS_PCH_NOP(dev))
                return;
 
-       if (HAS_PCH_IBX(dev)) {
+       if (HAS_PCH_IBX(dev))
                mask = SDE_GMBUS | SDE_AUX_MASK | SDE_POISON;
-       } else {
+       else
                mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT;
 
-               I915_WRITE(SERR_INT, I915_READ(SERR_INT));
-       }
-
-       I915_WRITE(SDEIIR, I915_READ(SDEIIR));
+       GEN5_ASSERT_IIR_IS_ZERO(SDEIIR);
        I915_WRITE(SDEIMR, ~mask);
 }
 
@@ -2965,10 +3273,7 @@ static void gen5_gt_irq_postinstall(struct drm_device *dev)
                gt_irqs |= GT_BLT_USER_INTERRUPT | GT_BSD_USER_INTERRUPT;
        }
 
-       I915_WRITE(GTIIR, I915_READ(GTIIR));
-       I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
-       I915_WRITE(GTIER, gt_irqs);
-       POSTING_READ(GTIER);
+       GEN5_IRQ_INIT(GT, dev_priv->gt_irq_mask, gt_irqs);
 
        if (INTEL_INFO(dev)->gen >= 6) {
                pm_irqs |= dev_priv->pm_rps_events;
@@ -2977,10 +3282,7 @@ static void gen5_gt_irq_postinstall(struct drm_device *dev)
                        pm_irqs |= PM_VEBOX_USER_INTERRUPT;
 
                dev_priv->pm_irq_mask = 0xffffffff;
-               I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
-               I915_WRITE(GEN6_PMIMR, dev_priv->pm_irq_mask);
-               I915_WRITE(GEN6_PMIER, pm_irqs);
-               POSTING_READ(GEN6_PMIER);
+               GEN5_IRQ_INIT(GEN6_PM, dev_priv->pm_irq_mask, pm_irqs);
        }
 }
 
@@ -2997,8 +3299,6 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
                                DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB);
                extra_mask = (DE_PIPEC_VBLANK_IVB | DE_PIPEB_VBLANK_IVB |
                              DE_PIPEA_VBLANK_IVB | DE_ERR_INT_IVB);
-
-               I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT));
        } else {
                display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
                                DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE |
@@ -3011,11 +3311,11 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
 
        dev_priv->irq_mask = ~display_mask;
 
-       /* should always can generate irq */
-       I915_WRITE(DEIIR, I915_READ(DEIIR));
-       I915_WRITE(DEIMR, dev_priv->irq_mask);
-       I915_WRITE(DEIER, display_mask | extra_mask);
-       POSTING_READ(DEIER);
+       I915_WRITE(HWSTAM, 0xeffe);
+
+       ibx_irq_pre_postinstall(dev);
+
+       GEN5_IRQ_INIT(DE, dev_priv->irq_mask, display_mask | extra_mask);
 
        gen5_gt_irq_postinstall(dev);
 
@@ -3175,21 +3475,16 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
                GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT
                };
 
-       for (i = 0; i < ARRAY_SIZE(gt_interrupts); i++) {
-               u32 tmp = I915_READ(GEN8_GT_IIR(i));
-               if (tmp)
-                       DRM_ERROR("Interrupt (%d) should have been masked in pre-install 0x%08x\n",
-                                 i, tmp);
-               I915_WRITE(GEN8_GT_IMR(i), ~gt_interrupts[i]);
-               I915_WRITE(GEN8_GT_IER(i), gt_interrupts[i]);
-       }
-       POSTING_READ(GEN8_GT_IER(0));
+       for (i = 0; i < ARRAY_SIZE(gt_interrupts); i++)
+               GEN8_IRQ_INIT_NDX(GT, i, ~gt_interrupts[i], gt_interrupts[i]);
+
+       dev_priv->pm_irq_mask = 0xffffffff;
 }
 
 static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
 {
        struct drm_device *dev = dev_priv->dev;
-       uint32_t de_pipe_masked = GEN8_PIPE_FLIP_DONE |
+       uint32_t de_pipe_masked = GEN8_PIPE_PRIMARY_FLIP_DONE |
                GEN8_PIPE_CDCLK_CRC_DONE |
                GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
        uint32_t de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK |
@@ -3199,25 +3494,19 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
        dev_priv->de_irq_mask[PIPE_B] = ~de_pipe_masked;
        dev_priv->de_irq_mask[PIPE_C] = ~de_pipe_masked;
 
-       for_each_pipe(pipe) {
-               u32 tmp = I915_READ(GEN8_DE_PIPE_IIR(pipe));
-               if (tmp)
-                       DRM_ERROR("Interrupt (%d) should have been masked in pre-install 0x%08x\n",
-                                 pipe, tmp);
-               I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]);
-               I915_WRITE(GEN8_DE_PIPE_IER(pipe), de_pipe_enables);
-       }
-       POSTING_READ(GEN8_DE_PIPE_ISR(0));
+       for_each_pipe(pipe)
+               GEN8_IRQ_INIT_NDX(DE_PIPE, pipe, dev_priv->de_irq_mask[pipe],
+                                 de_pipe_enables);
 
-       I915_WRITE(GEN8_DE_PORT_IMR, ~GEN8_AUX_CHANNEL_A);
-       I915_WRITE(GEN8_DE_PORT_IER, GEN8_AUX_CHANNEL_A);
-       POSTING_READ(GEN8_DE_PORT_IER);
+       GEN5_IRQ_INIT(GEN8_DE_PORT_, ~GEN8_AUX_CHANNEL_A, GEN8_AUX_CHANNEL_A);
 }
 
 static int gen8_irq_postinstall(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
+       ibx_irq_pre_postinstall(dev);
+
        gen8_gt_irq_postinstall(dev_priv);
        gen8_de_irq_postinstall(dev_priv);
 
@@ -3229,44 +3518,55 @@ static int gen8_irq_postinstall(struct drm_device *dev)
        return 0;
 }
 
-static void gen8_irq_uninstall(struct drm_device *dev)
+static int cherryview_irq_postinstall(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 enable_mask = I915_DISPLAY_PORT_INTERRUPT |
+               I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
+               I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
+               I915_DISPLAY_PIPE_C_EVENT_INTERRUPT;
+       u32 pipestat_enable = PLANE_FLIP_DONE_INT_STATUS_VLV |
+               PIPE_CRC_DONE_INTERRUPT_STATUS;
+       unsigned long irqflags;
        int pipe;
 
-       if (!dev_priv)
-               return;
+       /*
+        * Leave vblank interrupts masked initially.  enable/disable will
+        * toggle them based on usage.
+        */
+       dev_priv->irq_mask = ~enable_mask;
 
-       I915_WRITE(GEN8_MASTER_IRQ, 0);
+       for_each_pipe(pipe)
+               I915_WRITE(PIPESTAT(pipe), 0xffff);
 
-#define GEN8_IRQ_FINI_NDX(type, which) do { \
-               I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \
-               I915_WRITE(GEN8_##type##_IER(which), 0); \
-               I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff); \
-       } while (0)
+       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS);
+       for_each_pipe(pipe)
+               i915_enable_pipestat(dev_priv, pipe, pipestat_enable);
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
-#define GEN8_IRQ_FINI(type) do { \
-               I915_WRITE(GEN8_##type##_IMR, 0xffffffff); \
-               I915_WRITE(GEN8_##type##_IER, 0); \
-               I915_WRITE(GEN8_##type##_IIR, 0xffffffff); \
-       } while (0)
+       I915_WRITE(VLV_IIR, 0xffffffff);
+       I915_WRITE(VLV_IMR, dev_priv->irq_mask);
+       I915_WRITE(VLV_IER, enable_mask);
 
-       GEN8_IRQ_FINI_NDX(GT, 0);
-       GEN8_IRQ_FINI_NDX(GT, 1);
-       GEN8_IRQ_FINI_NDX(GT, 2);
-       GEN8_IRQ_FINI_NDX(GT, 3);
+       gen8_gt_irq_postinstall(dev_priv);
 
-       for_each_pipe(pipe) {
-               GEN8_IRQ_FINI_NDX(DE_PIPE, pipe);
-       }
+       I915_WRITE(GEN8_MASTER_IRQ, MASTER_INTERRUPT_ENABLE);
+       POSTING_READ(GEN8_MASTER_IRQ);
 
-       GEN8_IRQ_FINI(DE_PORT);
-       GEN8_IRQ_FINI(DE_MISC);
-       GEN8_IRQ_FINI(PCU);
-#undef GEN8_IRQ_FINI
-#undef GEN8_IRQ_FINI_NDX
+       return 0;
+}
 
-       POSTING_READ(GEN8_PCU_IIR);
+static void gen8_irq_uninstall(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (!dev_priv)
+               return;
+
+       intel_hpd_irq_uninstall(dev_priv);
+
+       gen8_irq_reset(dev);
 }
 
 static void valleyview_irq_uninstall(struct drm_device *dev)
@@ -3278,6 +3578,8 @@ static void valleyview_irq_uninstall(struct drm_device *dev)
        if (!dev_priv)
                return;
 
+       I915_WRITE(VLV_MASTER_IER, 0);
+
        intel_hpd_irq_uninstall(dev_priv);
 
        for_each_pipe(pipe)
@@ -3300,35 +3602,67 @@ static void valleyview_irq_uninstall(struct drm_device *dev)
        POSTING_READ(VLV_IER);
 }
 
-static void ironlake_irq_uninstall(struct drm_device *dev)
+static void cherryview_irq_uninstall(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       int pipe;
 
        if (!dev_priv)
                return;
 
-       intel_hpd_irq_uninstall(dev_priv);
+       I915_WRITE(GEN8_MASTER_IRQ, 0);
+       POSTING_READ(GEN8_MASTER_IRQ);
 
-       I915_WRITE(HWSTAM, 0xffffffff);
+#define GEN8_IRQ_FINI_NDX(type, which)                         \
+do {                                                           \
+       I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff);       \
+       I915_WRITE(GEN8_##type##_IER(which), 0);                \
+       I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff);       \
+       POSTING_READ(GEN8_##type##_IIR(which));                 \
+       I915_WRITE(GEN8_##type##_IIR(which), 0xffffffff);       \
+} while (0)
+
+#define GEN8_IRQ_FINI(type)                            \
+do {                                                   \
+       I915_WRITE(GEN8_##type##_IMR, 0xffffffff);      \
+       I915_WRITE(GEN8_##type##_IER, 0);               \
+       I915_WRITE(GEN8_##type##_IIR, 0xffffffff);      \
+       POSTING_READ(GEN8_##type##_IIR);                \
+       I915_WRITE(GEN8_##type##_IIR, 0xffffffff);      \
+} while (0)
 
-       I915_WRITE(DEIMR, 0xffffffff);
-       I915_WRITE(DEIER, 0x0);
-       I915_WRITE(DEIIR, I915_READ(DEIIR));
-       if (IS_GEN7(dev))
-               I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT));
+       GEN8_IRQ_FINI_NDX(GT, 0);
+       GEN8_IRQ_FINI_NDX(GT, 1);
+       GEN8_IRQ_FINI_NDX(GT, 2);
+       GEN8_IRQ_FINI_NDX(GT, 3);
 
-       I915_WRITE(GTIMR, 0xffffffff);
-       I915_WRITE(GTIER, 0x0);
-       I915_WRITE(GTIIR, I915_READ(GTIIR));
+       GEN8_IRQ_FINI(PCU);
 
-       if (HAS_PCH_NOP(dev))
+#undef GEN8_IRQ_FINI
+#undef GEN8_IRQ_FINI_NDX
+
+       I915_WRITE(PORT_HOTPLUG_EN, 0);
+       I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
+
+       for_each_pipe(pipe)
+               I915_WRITE(PIPESTAT(pipe), 0xffff);
+
+       I915_WRITE(VLV_IMR, 0xffffffff);
+       I915_WRITE(VLV_IER, 0x0);
+       I915_WRITE(VLV_IIR, 0xffffffff);
+       POSTING_READ(VLV_IIR);
+}
+
+static void ironlake_irq_uninstall(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (!dev_priv)
                return;
 
-       I915_WRITE(SDEIMR, 0xffffffff);
-       I915_WRITE(SDEIER, 0x0);
-       I915_WRITE(SDEIIR, I915_READ(SDEIIR));
-       if (HAS_PCH_CPT(dev) || HAS_PCH_LPT(dev))
-               I915_WRITE(SERR_INT, I915_READ(SERR_INT));
+       intel_hpd_irq_uninstall(dev_priv);
+
+       ironlake_irq_reset(dev);
 }
 
 static void i8xx_irq_preinstall(struct drm_device * dev)
@@ -3386,7 +3720,7 @@ static bool i8xx_handle_vblank(struct drm_device *dev,
        struct drm_i915_private *dev_priv = dev->dev_private;
        u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane);
 
-       if (!drm_handle_vblank(dev, pipe))
+       if (!intel_pipe_handle_vblank(dev, pipe))
                return false;
 
        if ((iir & flip_pending) == 0)
@@ -3410,7 +3744,7 @@ static bool i8xx_handle_vblank(struct drm_device *dev,
 
 static irqreturn_t i8xx_irq_handler(int irq, void *arg)
 {
-       struct drm_device *dev = (struct drm_device *) arg;
+       struct drm_device *dev = arg;
        struct drm_i915_private *dev_priv = dev->dev_private;
        u16 iir, new_iir;
        u32 pipe_stats[2];
@@ -3571,7 +3905,7 @@ static bool i915_handle_vblank(struct drm_device *dev,
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane);
 
-       if (!drm_handle_vblank(dev, pipe))
+       if (!intel_pipe_handle_vblank(dev, pipe))
                return false;
 
        if ((iir & flip_pending) == 0)
@@ -3595,7 +3929,7 @@ static bool i915_handle_vblank(struct drm_device *dev,
 
 static irqreturn_t i915_irq_handler(int irq, void *arg)
 {
-       struct drm_device *dev = (struct drm_device *) arg;
+       struct drm_device *dev = arg;
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 iir, new_iir, pipe_stats[I915_MAX_PIPES];
        unsigned long irqflags;
@@ -3636,16 +3970,9 @@ 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)) {
-                       u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
-                       u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
-
-                       intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
-
-                       I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
-                       POSTING_READ(PORT_HOTPLUG_STAT);
-               }
+               if (I915_HAS_HOTPLUG(dev) &&
+                   iir & I915_DISPLAY_PORT_INTERRUPT)
+                       i9xx_hpd_irq_handler(dev);
 
                I915_WRITE(IIR, iir & ~flip_mask);
                new_iir = I915_READ(IIR); /* Flush posted writes */
@@ -3832,7 +4159,7 @@ static void i915_hpd_irq_setup(struct drm_device *dev)
 
 static irqreturn_t i965_irq_handler(int irq, void *arg)
 {
-       struct drm_device *dev = (struct drm_device *) arg;
+       struct drm_device *dev = arg;
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 iir, new_iir;
        u32 pipe_stats[I915_MAX_PIPES];
@@ -3879,22 +4206,8 @@ 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) {
-                       u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
-                       u32 hotplug_trigger = hotplug_status & (IS_G4X(dev) ?
-                                                                 HOTPLUG_INT_STATUS_G4X :
-                                                                 HOTPLUG_INT_STATUS_I915);
-
-                       intel_hpd_irq_handler(dev, hotplug_trigger,
-                                             IS_G4X(dev) ? hpd_status_g4x : hpd_status_i915);
-
-                       if (IS_G4X(dev) &&
-                           (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X))
-                               dp_aux_irq_handler(dev);
-
-                       I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
-                       I915_READ(PORT_HOTPLUG_STAT);
-               }
+               if (iir & I915_DISPLAY_PORT_INTERRUPT)
+                       i9xx_hpd_irq_handler(dev);
 
                I915_WRITE(IIR, iir & ~flip_mask);
                new_iir = I915_READ(IIR); /* Flush posted writes */
@@ -3997,7 +4310,7 @@ static void intel_hpd_irq_reenable(unsigned long data)
                        if (intel_connector->encoder->hpd_pin == i) {
                                if (connector->polled != intel_connector->polled)
                                        DRM_DEBUG_DRIVER("Reenabling HPD on connector %s\n",
-                                                        drm_get_connector_name(connector));
+                                                        connector->name);
                                connector->polled = intel_connector->polled;
                                if (!connector->polled)
                                        connector->polled = DRM_CONNECTOR_POLL_HPD;
@@ -4045,7 +4358,15 @@ void intel_irq_init(struct drm_device *dev)
                dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;
        }
 
-       if (IS_VALLEYVIEW(dev)) {
+       if (IS_CHERRYVIEW(dev)) {
+               dev->driver->irq_handler = cherryview_irq_handler;
+               dev->driver->irq_preinstall = cherryview_irq_preinstall;
+               dev->driver->irq_postinstall = cherryview_irq_postinstall;
+               dev->driver->irq_uninstall = cherryview_irq_uninstall;
+               dev->driver->enable_vblank = valleyview_enable_vblank;
+               dev->driver->disable_vblank = valleyview_disable_vblank;
+               dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
+       } else if (IS_VALLEYVIEW(dev)) {
                dev->driver->irq_handler = valleyview_irq_handler;
                dev->driver->irq_preinstall = valleyview_irq_preinstall;
                dev->driver->irq_postinstall = valleyview_irq_postinstall;
@@ -4055,7 +4376,7 @@ void intel_irq_init(struct drm_device *dev)
                dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
        } else if (IS_GEN8(dev)) {
                dev->driver->irq_handler = gen8_irq_handler;
-               dev->driver->irq_preinstall = gen8_irq_preinstall;
+               dev->driver->irq_preinstall = gen8_irq_reset;
                dev->driver->irq_postinstall = gen8_irq_postinstall;
                dev->driver->irq_uninstall = gen8_irq_uninstall;
                dev->driver->enable_vblank = gen8_enable_vblank;
@@ -4063,7 +4384,7 @@ void intel_irq_init(struct drm_device *dev)
                dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup;
        } else if (HAS_PCH_SPLIT(dev)) {
                dev->driver->irq_handler = ironlake_irq_handler;
-               dev->driver->irq_preinstall = ironlake_irq_preinstall;
+               dev->driver->irq_preinstall = ironlake_irq_reset;
                dev->driver->irq_postinstall = ironlake_irq_postinstall;
                dev->driver->irq_uninstall = ironlake_irq_uninstall;
                dev->driver->enable_vblank = ironlake_enable_vblank;
@@ -4121,57 +4442,20 @@ void intel_hpd_init(struct drm_device *dev)
 }
 
 /* Disable interrupts so we can allow runtime PM. */
-void hsw_runtime_pm_disable_interrupts(struct drm_device *dev)
+void intel_runtime_pm_disable_interrupts(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       unsigned long irqflags;
-
-       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-
-       dev_priv->pm.regsave.deimr = I915_READ(DEIMR);
-       dev_priv->pm.regsave.sdeimr = I915_READ(SDEIMR);
-       dev_priv->pm.regsave.gtimr = I915_READ(GTIMR);
-       dev_priv->pm.regsave.gtier = I915_READ(GTIER);
-       dev_priv->pm.regsave.gen6_pmimr = I915_READ(GEN6_PMIMR);
-
-       ironlake_disable_display_irq(dev_priv, 0xffffffff);
-       ibx_disable_display_interrupt(dev_priv, 0xffffffff);
-       ilk_disable_gt_irq(dev_priv, 0xffffffff);
-       snb_disable_pm_irq(dev_priv, 0xffffffff);
 
+       dev->driver->irq_uninstall(dev);
        dev_priv->pm.irqs_disabled = true;
-
-       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
 
 /* Restore interrupts so we can recover from runtime PM. */
-void hsw_runtime_pm_restore_interrupts(struct drm_device *dev)
+void intel_runtime_pm_restore_interrupts(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       unsigned long irqflags;
-       uint32_t val;
-
-       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-
-       val = I915_READ(DEIMR);
-       WARN(val != 0xffffffff, "DEIMR is 0x%08x\n", val);
-
-       val = I915_READ(SDEIMR);
-       WARN(val != 0xffffffff, "SDEIMR is 0x%08x\n", val);
-
-       val = I915_READ(GTIMR);
-       WARN(val != 0xffffffff, "GTIMR is 0x%08x\n", val);
-
-       val = I915_READ(GEN6_PMIMR);
-       WARN(val != 0xffffffff, "GEN6_PMIMR is 0x%08x\n", val);
 
        dev_priv->pm.irqs_disabled = false;
-
-       ironlake_enable_display_irq(dev_priv, ~dev_priv->pm.regsave.deimr);
-       ibx_enable_display_interrupt(dev_priv, ~dev_priv->pm.regsave.sdeimr);
-       ilk_enable_gt_irq(dev_priv, ~dev_priv->pm.regsave.gtimr);
-       snb_enable_pm_irq(dev_priv, ~dev_priv->pm.regsave.gen6_pmimr);
-       I915_WRITE(GTIER, dev_priv->pm.regsave.gtier);
-
-       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       dev->driver->irq_preinstall(dev);
+       dev->driver->irq_postinstall(dev);
 }