Merge tag 'bdw-stage1-2013-11-08-v2' of git://people.freedesktop.org/~danvet/drm...
[linux-drm-fsl-dcu.git] / drivers / gpu / drm / i915 / i915_irq.c
index 4b91228fd9bd8e50e1319816a9fe53b6f166ec68..5d1dedc02f159c8b7a21d23a940df9c5bf0c2bd2 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <linux/sysrq.h>
 #include <linux/slab.h>
+#include <linux/circ_buf.h>
 #include <drm/drmP.h>
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
@@ -269,6 +270,21 @@ static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev,
        }
 }
 
+static void broadwell_set_fifo_underrun_reporting(struct drm_device *dev,
+                                                 enum pipe pipe, bool enable)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       assert_spin_locked(&dev_priv->irq_lock);
+
+       if (enable)
+               dev_priv->de_irq_mask[pipe] &= ~GEN8_PIPE_FIFO_UNDERRUN;
+       else
+               dev_priv->de_irq_mask[pipe] |= GEN8_PIPE_FIFO_UNDERRUN;
+       I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]);
+       POSTING_READ(GEN8_DE_PIPE_IMR(pipe));
+}
+
 /**
  * ibx_display_interrupt_update - update SDEIMR
  * @dev_priv: driver private
@@ -381,6 +397,8 @@ bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
                ironlake_set_fifo_underrun_reporting(dev, pipe, enable);
        else if (IS_GEN7(dev))
                ivybridge_set_fifo_underrun_reporting(dev, pipe, enable);
+       else if (IS_GEN8(dev))
+               broadwell_set_fifo_underrun_reporting(dev, pipe, enable);
 
 done:
        spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
@@ -441,7 +459,7 @@ done:
 
 
 void
-i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
+i915_enable_pipestat(drm_i915_private_t *dev_priv, enum pipe pipe, u32 mask)
 {
        u32 reg = PIPESTAT(pipe);
        u32 pipestat = I915_READ(reg) & 0x7fff0000;
@@ -458,7 +476,7 @@ i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
 }
 
 void
-i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
+i915_disable_pipestat(drm_i915_private_t *dev_priv, enum pipe pipe, u32 mask)
 {
        u32 reg = PIPESTAT(pipe);
        u32 pipestat = I915_READ(reg) & 0x7fff0000;
@@ -486,9 +504,10 @@ static void i915_enable_asle_pipestat(struct drm_device *dev)
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 
-       i915_enable_pipestat(dev_priv, 1, PIPE_LEGACY_BLC_EVENT_ENABLE);
+       i915_enable_pipestat(dev_priv, PIPE_B, PIPE_LEGACY_BLC_EVENT_ENABLE);
        if (INTEL_INFO(dev)->gen >= 4)
-               i915_enable_pipestat(dev_priv, 0, PIPE_LEGACY_BLC_EVENT_ENABLE);
+               i915_enable_pipestat(dev_priv, PIPE_A,
+                                    PIPE_LEGACY_BLC_EVENT_ENABLE);
 
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
@@ -518,6 +537,12 @@ i915_pipe_enabled(struct drm_device *dev, int pipe)
        }
 }
 
+static u32 i8xx_get_vblank_counter(struct drm_device *dev, int pipe)
+{
+       /* Gen2 doesn't have a hardware frame counter */
+       return 0;
+}
+
 /* Called from drm generic code, passed a 'crtc', which
  * we use as a pipe index
  */
@@ -526,7 +551,7 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        unsigned long high_frame;
        unsigned long low_frame;
-       u32 high1, high2, low;
+       u32 high1, high2, low, pixel, vbl_start;
 
        if (!i915_pipe_enabled(dev, pipe)) {
                DRM_DEBUG_DRIVER("trying to get vblank count for disabled "
@@ -534,6 +559,24 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
                return 0;
        }
 
+       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               struct intel_crtc *intel_crtc =
+                       to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+               const struct drm_display_mode *mode =
+                       &intel_crtc->config.adjusted_mode;
+
+               vbl_start = mode->crtc_vblank_start * mode->crtc_htotal;
+       } else {
+               enum transcoder cpu_transcoder =
+                       intel_pipe_to_cpu_transcoder(dev_priv, pipe);
+               u32 htotal;
+
+               htotal = ((I915_READ(HTOTAL(cpu_transcoder)) >> 16) & 0x1fff) + 1;
+               vbl_start = (I915_READ(VBLANK(cpu_transcoder)) & 0x1fff) + 1;
+
+               vbl_start *= htotal;
+       }
+
        high_frame = PIPEFRAME(pipe);
        low_frame = PIPEFRAMEPIXEL(pipe);
 
@@ -544,13 +587,20 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
         */
        do {
                high1 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK;
-               low   = I915_READ(low_frame)  & PIPE_FRAME_LOW_MASK;
+               low   = I915_READ(low_frame);
                high2 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK;
        } while (high1 != high2);
 
        high1 >>= PIPE_FRAME_HIGH_SHIFT;
+       pixel = low & PIPE_PIXEL_MASK;
        low >>= PIPE_FRAME_LOW_SHIFT;
-       return (high1 << 8) | low;
+
+       /*
+        * The frame counter increments at beginning of active.
+        * Cook up a vblank counter by also checking the pixel
+        * counter against vblank start.
+        */
+       return ((high1 << 8) | low) + (pixel >= vbl_start);
 }
 
 static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
@@ -567,66 +617,163 @@ static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
        return I915_READ(reg);
 }
 
+/* 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__))
+#define __raw_i915_read16(dev_priv__, reg__) readw((dev_priv__)->regs + (reg__))
+
+static bool intel_pipe_in_vblank_locked(struct drm_device *dev, enum pipe pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t status;
+       int reg;
+
+       if (IS_VALLEYVIEW(dev)) {
+               status = pipe == PIPE_A ?
+                       I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT :
+                       I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
+
+               reg = VLV_ISR;
+       } else if (IS_GEN2(dev)) {
+               status = pipe == PIPE_A ?
+                       I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT :
+                       I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
+
+               reg = ISR;
+       } else if (INTEL_INFO(dev)->gen < 5) {
+               status = pipe == PIPE_A ?
+                       I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT :
+                       I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
+
+               reg = ISR;
+       } else if (INTEL_INFO(dev)->gen < 7) {
+               status = pipe == PIPE_A ?
+                       DE_PIPEA_VBLANK :
+                       DE_PIPEB_VBLANK;
+
+               reg = DEISR;
+       } else {
+               switch (pipe) {
+               default:
+               case PIPE_A:
+                       status = DE_PIPEA_VBLANK_IVB;
+                       break;
+               case PIPE_B:
+                       status = DE_PIPEB_VBLANK_IVB;
+                       break;
+               case PIPE_C:
+                       status = DE_PIPEC_VBLANK_IVB;
+                       break;
+               }
+
+               reg = DEISR;
+       }
+
+       if (IS_GEN2(dev))
+               return __raw_i915_read16(dev_priv, reg) & status;
+       else
+               return __raw_i915_read32(dev_priv, reg) & status;
+}
+
 static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
-                            int *vpos, int *hpos)
+                            int *vpos, int *hpos, ktime_t *stime, ktime_t *etime)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       u32 vbl = 0, position = 0;
+       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);
+       const struct drm_display_mode *mode = &intel_crtc->config.adjusted_mode;
+       int position;
        int vbl_start, vbl_end, htotal, vtotal;
        bool in_vbl = true;
        int ret = 0;
-       enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
-                                                                     pipe);
+       unsigned long irqflags;
 
-       if (!i915_pipe_enabled(dev, pipe)) {
+       if (!intel_crtc->active) {
                DRM_DEBUG_DRIVER("trying to get scanoutpos for disabled "
                                 "pipe %c\n", pipe_name(pipe));
                return 0;
        }
 
-       /* Get vtotal. */
-       vtotal = 1 + ((I915_READ(VTOTAL(cpu_transcoder)) >> 16) & 0x1fff);
+       htotal = mode->crtc_htotal;
+       vtotal = mode->crtc_vtotal;
+       vbl_start = mode->crtc_vblank_start;
+       vbl_end = mode->crtc_vblank_end;
 
-       if (INTEL_INFO(dev)->gen >= 4) {
+       ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
+
+       /*
+        * Lock uncore.lock, as we will do multiple timing critical raw
+        * register reads, potentially with preemption disabled, so the
+        * 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. */
+       if (stime)
+               *stime = ktime_get();
+
+       if (IS_GEN2(dev) || IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
                /* No obvious pixelcount register. Only query vertical
                 * scanout position from Display scan line register.
                 */
-               position = I915_READ(PIPEDSL(pipe));
+               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;
 
-               /* Decode into vertical scanout position. Don't have
-                * horizontal scanout position.
+               /*
+                * 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.
                 */
-               *vpos = position & 0x1fff;
-               *hpos = 0;
+               in_vbl = intel_pipe_in_vblank_locked(dev, pipe);
+               if ((in_vbl && position == vbl_start - 1) ||
+                   (!in_vbl && position == vbl_end - 1))
+                       position = (position + 1) % vtotal;
        } else {
                /* Have access to pixelcount since start of frame.
                 * We can split this into vertical and horizontal
                 * scanout position.
                 */
-               position = (I915_READ(PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT;
+               position = (__raw_i915_read32(dev_priv, PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT;
 
-               htotal = 1 + ((I915_READ(HTOTAL(cpu_transcoder)) >> 16) & 0x1fff);
-               *vpos = position / htotal;
-               *hpos = position - (*vpos * htotal);
+               /* convert to pixel counts */
+               vbl_start *= htotal;
+               vbl_end *= htotal;
+               vtotal *= htotal;
        }
 
-       /* Query vblank area. */
-       vbl = I915_READ(VBLANK(cpu_transcoder));
+       /* Get optional system timestamp after query. */
+       if (etime)
+               *etime = ktime_get();
 
-       /* Test position against vblank region. */
-       vbl_start = vbl & 0x1fff;
-       vbl_end = (vbl >> 16) & 0x1fff;
+       /* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */
 
-       if ((*vpos < vbl_start) || (*vpos > vbl_end))
-               in_vbl = false;
+       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 
-       /* Inside "upper part" of vblank area? Apply corrective offset: */
-       if (in_vbl && (*vpos >= vbl_start))
-               *vpos = *vpos - vtotal;
+       in_vbl = position >= vbl_start && position < vbl_end;
 
-       /* Readouts valid? */
-       if (vbl > 0)
-               ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
+       /*
+        * While in vblank, position will be negative
+        * counting up towards 0 at vbl_end. And outside
+        * vblank, position will be positive counting
+        * up since vbl_end.
+        */
+       if (position >= vbl_start)
+               position -= vbl_end;
+       else
+               position += vtotal - vbl_end;
+
+       if (IS_GEN2(dev) || IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
+               *vpos = position;
+               *hpos = 0;
+       } else {
+               *vpos = position / htotal;
+               *hpos = position - (*vpos * htotal);
+       }
 
        /* In vblank? */
        if (in_vbl)
@@ -665,7 +812,8 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe,
                                                     crtc);
 }
 
-static int intel_hpd_irq_event(struct drm_device *dev, struct drm_connector *connector)
+static bool intel_hpd_irq_event(struct drm_device *dev,
+                               struct drm_connector *connector)
 {
        enum drm_connector_status old_status;
 
@@ -673,11 +821,16 @@ static int intel_hpd_irq_event(struct drm_device *dev, struct drm_connector *con
        old_status = connector->status;
 
        connector->status = connector->funcs->detect(connector, false);
-       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
+       if (old_status == connector->status)
+               return false;
+
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n",
                      connector->base.id,
                      drm_get_connector_name(connector),
-                     old_status, connector->status);
-       return (old_status != connector->status);
+                     drm_get_connector_status_name(old_status),
+                     drm_get_connector_status_name(connector->status));
+
+       return true;
 }
 
 /*
@@ -801,7 +954,7 @@ static void notify_ring(struct drm_device *dev,
        if (ring->obj == NULL)
                return;
 
-       trace_i915_gem_request_complete(ring, ring->get_seqno(ring, false));
+       trace_i915_gem_request_complete(ring);
 
        wake_up_all(&ring->irq_queue);
        i915_queue_hangcheck(dev);
@@ -812,7 +965,7 @@ static void gen6_pm_rps_work(struct work_struct *work)
        drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
                                                    rps.work);
        u32 pm_iir;
-       u8 new_delay;
+       int new_delay, adj;
 
        spin_lock_irq(&dev_priv->irq_lock);
        pm_iir = dev_priv->rps.pm_iir;
@@ -829,40 +982,49 @@ static void gen6_pm_rps_work(struct work_struct *work)
 
        mutex_lock(&dev_priv->rps.hw_lock);
 
+       adj = dev_priv->rps.last_adj;
        if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
-               new_delay = dev_priv->rps.cur_delay + 1;
+               if (adj > 0)
+                       adj *= 2;
+               else
+                       adj = 1;
+               new_delay = dev_priv->rps.cur_delay + adj;
 
                /*
                 * For better performance, jump directly
                 * to RPe if we're below it.
                 */
-               if (IS_VALLEYVIEW(dev_priv->dev) &&
-                   dev_priv->rps.cur_delay < dev_priv->rps.rpe_delay)
+               if (new_delay < dev_priv->rps.rpe_delay)
+                       new_delay = dev_priv->rps.rpe_delay;
+       } else if (pm_iir & GEN6_PM_RP_DOWN_TIMEOUT) {
+               if (dev_priv->rps.cur_delay > dev_priv->rps.rpe_delay)
                        new_delay = dev_priv->rps.rpe_delay;
-       } else
-               new_delay = dev_priv->rps.cur_delay - 1;
+               else
+                       new_delay = dev_priv->rps.min_delay;
+               adj = 0;
+       } else if (pm_iir & GEN6_PM_RP_DOWN_THRESHOLD) {
+               if (adj < 0)
+                       adj *= 2;
+               else
+                       adj = -1;
+               new_delay = dev_priv->rps.cur_delay + adj;
+       } else { /* unknown event */
+               new_delay = dev_priv->rps.cur_delay;
+       }
 
        /* sysfs frequency interfaces may have snuck in while servicing the
         * interrupt
         */
-       if (new_delay >= dev_priv->rps.min_delay &&
-           new_delay <= dev_priv->rps.max_delay) {
-               if (IS_VALLEYVIEW(dev_priv->dev))
-                       valleyview_set_rps(dev_priv->dev, new_delay);
-               else
-                       gen6_set_rps(dev_priv->dev, new_delay);
-       }
-
-       if (IS_VALLEYVIEW(dev_priv->dev)) {
-               /*
-                * On VLV, when we enter RC6 we may not be at the minimum
-                * voltage level, so arm a timer to check.  It should only
-                * fire when there's activity or once after we've entered
-                * RC6, and then won't be re-armed until the next RPS interrupt.
-                */
-               mod_delayed_work(dev_priv->wq, &dev_priv->rps.vlv_work,
-                                msecs_to_jiffies(100));
-       }
+       if (new_delay < (int)dev_priv->rps.min_delay)
+               new_delay = dev_priv->rps.min_delay;
+       if (new_delay > (int)dev_priv->rps.max_delay)
+               new_delay = dev_priv->rps.max_delay;
+       dev_priv->rps.last_adj = new_delay - dev_priv->rps.cur_delay;
+
+       if (IS_VALLEYVIEW(dev_priv->dev))
+               valleyview_set_rps(dev_priv->dev, new_delay);
+       else
+               gen6_set_rps(dev_priv->dev, new_delay);
 
        mutex_unlock(&dev_priv->rps.hw_lock);
 }
@@ -882,9 +1044,10 @@ static void ivybridge_parity_work(struct work_struct *work)
        drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
                                                    l3_parity.error_work);
        u32 error_status, row, bank, subbank;
-       char *parity_event[5];
+       char *parity_event[6];
        uint32_t misccpctl;
        unsigned long flags;
+       uint8_t slice = 0;
 
        /* We must turn off DOP level clock gating to access the L3 registers.
         * In order to prevent a get/put style interface, acquire struct mutex
@@ -892,55 +1055,81 @@ static void ivybridge_parity_work(struct work_struct *work)
         */
        mutex_lock(&dev_priv->dev->struct_mutex);
 
+       /* If we've screwed up tracking, just let the interrupt fire again */
+       if (WARN_ON(!dev_priv->l3_parity.which_slice))
+               goto out;
+
        misccpctl = I915_READ(GEN7_MISCCPCTL);
        I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
        POSTING_READ(GEN7_MISCCPCTL);
 
-       error_status = I915_READ(GEN7_L3CDERRST1);
-       row = GEN7_PARITY_ERROR_ROW(error_status);
-       bank = GEN7_PARITY_ERROR_BANK(error_status);
-       subbank = GEN7_PARITY_ERROR_SUBBANK(error_status);
+       while ((slice = ffs(dev_priv->l3_parity.which_slice)) != 0) {
+               u32 reg;
 
-       I915_WRITE(GEN7_L3CDERRST1, GEN7_PARITY_ERROR_VALID |
-                                   GEN7_L3CDERRST1_ENABLE);
-       POSTING_READ(GEN7_L3CDERRST1);
+               slice--;
+               if (WARN_ON_ONCE(slice >= NUM_L3_SLICES(dev_priv->dev)))
+                       break;
 
-       I915_WRITE(GEN7_MISCCPCTL, misccpctl);
+               dev_priv->l3_parity.which_slice &= ~(1<<slice);
 
-       spin_lock_irqsave(&dev_priv->irq_lock, flags);
-       ilk_enable_gt_irq(dev_priv, GT_RENDER_L3_PARITY_ERROR_INTERRUPT);
-       spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+               reg = GEN7_L3CDERRST1 + (slice * 0x200);
 
-       mutex_unlock(&dev_priv->dev->struct_mutex);
+               error_status = I915_READ(reg);
+               row = GEN7_PARITY_ERROR_ROW(error_status);
+               bank = GEN7_PARITY_ERROR_BANK(error_status);
+               subbank = GEN7_PARITY_ERROR_SUBBANK(error_status);
 
-       parity_event[0] = I915_L3_PARITY_UEVENT "=1";
-       parity_event[1] = kasprintf(GFP_KERNEL, "ROW=%d", row);
-       parity_event[2] = kasprintf(GFP_KERNEL, "BANK=%d", bank);
-       parity_event[3] = kasprintf(GFP_KERNEL, "SUBBANK=%d", subbank);
-       parity_event[4] = NULL;
+               I915_WRITE(reg, GEN7_PARITY_ERROR_VALID | GEN7_L3CDERRST1_ENABLE);
+               POSTING_READ(reg);
+
+               parity_event[0] = I915_L3_PARITY_UEVENT "=1";
+               parity_event[1] = kasprintf(GFP_KERNEL, "ROW=%d", row);
+               parity_event[2] = kasprintf(GFP_KERNEL, "BANK=%d", bank);
+               parity_event[3] = kasprintf(GFP_KERNEL, "SUBBANK=%d", subbank);
+               parity_event[4] = kasprintf(GFP_KERNEL, "SLICE=%d", slice);
+               parity_event[5] = NULL;
+
+               kobject_uevent_env(&dev_priv->dev->primary->kdev->kobj,
+                                  KOBJ_CHANGE, parity_event);
+
+               DRM_DEBUG("Parity error: Slice = %d, Row = %d, Bank = %d, Sub bank = %d.\n",
+                         slice, row, bank, subbank);
+
+               kfree(parity_event[4]);
+               kfree(parity_event[3]);
+               kfree(parity_event[2]);
+               kfree(parity_event[1]);
+       }
 
-       kobject_uevent_env(&dev_priv->dev->primary->kdev.kobj,
-                          KOBJ_CHANGE, parity_event);
+       I915_WRITE(GEN7_MISCCPCTL, misccpctl);
 
-       DRM_DEBUG("Parity error: Row = %d, Bank = %d, Sub bank = %d.\n",
-                 row, bank, subbank);
+out:
+       WARN_ON(dev_priv->l3_parity.which_slice);
+       spin_lock_irqsave(&dev_priv->irq_lock, flags);
+       ilk_enable_gt_irq(dev_priv, GT_PARITY_ERROR(dev_priv->dev));
+       spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
 
-       kfree(parity_event[3]);
-       kfree(parity_event[2]);
-       kfree(parity_event[1]);
+       mutex_unlock(&dev_priv->dev->struct_mutex);
 }
 
-static void ivybridge_parity_error_irq_handler(struct drm_device *dev)
+static void ivybridge_parity_error_irq_handler(struct drm_device *dev, u32 iir)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 
-       if (!HAS_L3_GPU_CACHE(dev))
+       if (!HAS_L3_DPF(dev))
                return;
 
        spin_lock(&dev_priv->irq_lock);
-       ilk_disable_gt_irq(dev_priv, GT_RENDER_L3_PARITY_ERROR_INTERRUPT);
+       ilk_disable_gt_irq(dev_priv, GT_PARITY_ERROR(dev));
        spin_unlock(&dev_priv->irq_lock);
 
+       iir &= GT_PARITY_ERROR(dev);
+       if (iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT_S1)
+               dev_priv->l3_parity.which_slice |= 1 << 1;
+
+       if (iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT)
+               dev_priv->l3_parity.which_slice |= 1 << 0;
+
        queue_work(dev_priv->wq, &dev_priv->l3_parity.error_work);
 }
 
@@ -975,8 +1164,58 @@ static void snb_gt_irq_handler(struct drm_device *dev,
                i915_handle_error(dev, false);
        }
 
-       if (gt_iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT)
-               ivybridge_parity_error_irq_handler(dev);
+       if (gt_iir & GT_PARITY_ERROR(dev))
+               ivybridge_parity_error_irq_handler(dev, gt_iir);
+}
+
+static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
+                                      struct drm_i915_private *dev_priv,
+                                      u32 master_ctl)
+{
+       u32 rcs, bcs, vcs;
+       uint32_t tmp = 0;
+       irqreturn_t ret = IRQ_NONE;
+
+       if (master_ctl & (GEN8_GT_RCS_IRQ | GEN8_GT_BCS_IRQ)) {
+               tmp = I915_READ(GEN8_GT_IIR(0));
+               if (tmp) {
+                       ret = IRQ_HANDLED;
+                       rcs = tmp >> GEN8_RCS_IRQ_SHIFT;
+                       bcs = tmp >> GEN8_BCS_IRQ_SHIFT;
+                       if (rcs & GT_RENDER_USER_INTERRUPT)
+                               notify_ring(dev, &dev_priv->ring[RCS]);
+                       if (bcs & GT_RENDER_USER_INTERRUPT)
+                               notify_ring(dev, &dev_priv->ring[BCS]);
+                       I915_WRITE(GEN8_GT_IIR(0), tmp);
+               } else
+                       DRM_ERROR("The master control interrupt lied (GT0)!\n");
+       }
+
+       if (master_ctl & GEN8_GT_VCS1_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]);
+                       I915_WRITE(GEN8_GT_IIR(1), tmp);
+               } else
+                       DRM_ERROR("The master control interrupt lied (GT1)!\n");
+       }
+
+       if (master_ctl & GEN8_GT_VECS_IRQ) {
+               tmp = I915_READ(GEN8_GT_IIR(3));
+               if (tmp) {
+                       ret = IRQ_HANDLED;
+                       vcs = tmp >> GEN8_VECS_IRQ_SHIFT;
+                       if (vcs & GT_RENDER_USER_INTERRUPT)
+                               notify_ring(dev, &dev_priv->ring[VECS]);
+                       I915_WRITE(GEN8_GT_IIR(3), tmp);
+               } else
+                       DRM_ERROR("The master control interrupt lied (GT3)!\n");
+       }
+
+       return ret;
 }
 
 #define HPD_STORM_DETECT_PERIOD 1000
@@ -1050,6 +1289,102 @@ static void dp_aux_irq_handler(struct drm_device *dev)
        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,
+                                        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;
+
+       spin_lock(&pipe_crc->lock);
+
+       if (!pipe_crc->entries) {
+               spin_unlock(&pipe_crc->lock);
+               DRM_ERROR("spurious interrupt\n");
+               return;
+       }
+
+       head = pipe_crc->head;
+       tail = pipe_crc->tail;
+
+       if (CIRC_SPACE(head, tail, INTEL_PIPE_CRC_ENTRIES_NR) < 1) {
+               spin_unlock(&pipe_crc->lock);
+               DRM_ERROR("CRC buffer overflowing\n");
+               return;
+       }
+
+       entry = &pipe_crc->entries[head];
+
+       entry->frame = dev->driver->get_vblank_counter(dev, pipe);
+       entry->crc[0] = crc0;
+       entry->crc[1] = crc1;
+       entry->crc[2] = crc2;
+       entry->crc[3] = crc3;
+       entry->crc[4] = crc4;
+
+       head = (head + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1);
+       pipe_crc->head = head;
+
+       spin_unlock(&pipe_crc->lock);
+
+       wake_up_interruptible(&pipe_crc->wq);
+}
+#else
+static inline void
+display_pipe_crc_irq_handler(struct drm_device *dev, 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)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       display_pipe_crc_irq_handler(dev, 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)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       display_pipe_crc_irq_handler(dev, 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)),
+                                    I915_READ(PIPE_CRC_RES_4_IVB(pipe)),
+                                    I915_READ(PIPE_CRC_RES_5_IVB(pipe)));
+}
+
+static void i9xx_pipe_crc_irq_handler(struct drm_device *dev, enum pipe pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t res1, res2;
+
+       if (INTEL_INFO(dev)->gen >= 3)
+               res1 = I915_READ(PIPE_CRC_RES_RES1_I915(pipe));
+       else
+               res1 = 0;
+
+       if (INTEL_INFO(dev)->gen >= 5 || IS_G4X(dev))
+               res2 = I915_READ(PIPE_CRC_RES_RES2_G4X(pipe));
+       else
+               res2 = 0;
+
+       display_pipe_crc_irq_handler(dev, pipe,
+                                    I915_READ(PIPE_CRC_RES_RED(pipe)),
+                                    I915_READ(PIPE_CRC_RES_GREEN(pipe)),
+                                    I915_READ(PIPE_CRC_RES_BLUE(pipe)),
+                                    res1, res2);
+}
+
 /* The RPS events need forcewake, so we add them to a work queue and mask their
  * IMR bits until the work is done. Other interrupts can be processed without
  * the work queue. */
@@ -1117,13 +1452,16 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
                spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
                for_each_pipe(pipe) {
-                       if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS)
+                       if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
                                drm_handle_vblank(dev, pipe);
 
                        if (pipe_stats[pipe] & PLANE_FLIPDONE_INT_STATUS_VLV) {
                                intel_prepare_page_flip(dev, pipe);
                                intel_finish_page_flip(dev, pipe);
                        }
+
+                       if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
+                               i9xx_pipe_crc_irq_handler(dev, pipe);
                }
 
                /* Consume port.  Then clear IIR or we'll miss events */
@@ -1212,21 +1550,26 @@ static void ivb_err_int_handler(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 err_int = I915_READ(GEN7_ERR_INT);
+       enum pipe pipe;
 
        if (err_int & ERR_INT_POISON)
                DRM_ERROR("Poison interrupt\n");
 
-       if (err_int & ERR_INT_FIFO_UNDERRUN_A)
-               if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_A, false))
-                       DRM_DEBUG_DRIVER("Pipe A FIFO underrun\n");
-
-       if (err_int & ERR_INT_FIFO_UNDERRUN_B)
-               if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_B, false))
-                       DRM_DEBUG_DRIVER("Pipe B FIFO underrun\n");
+       for_each_pipe(pipe) {
+               if (err_int & ERR_INT_FIFO_UNDERRUN(pipe)) {
+                       if (intel_set_cpu_fifo_underrun_reporting(dev, pipe,
+                                                                 false))
+                               DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n",
+                                                pipe_name(pipe));
+               }
 
-       if (err_int & ERR_INT_FIFO_UNDERRUN_C)
-               if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_C, false))
-                       DRM_DEBUG_DRIVER("Pipe C FIFO underrun\n");
+               if (err_int & ERR_INT_PIPE_CRC_DONE(pipe)) {
+                       if (IS_IVYBRIDGE(dev))
+                               ivb_pipe_crc_irq_handler(dev, pipe);
+                       else
+                               hsw_pipe_crc_irq_handler(dev, pipe);
+               }
+       }
 
        I915_WRITE(GEN7_ERR_INT, err_int);
 }
@@ -1297,6 +1640,7 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
 static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       enum pipe pipe;
 
        if (de_iir & DE_AUX_CHANNEL_A)
                dp_aux_irq_handler(dev);
@@ -1304,31 +1648,26 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
        if (de_iir & DE_GSE)
                intel_opregion_asle_intr(dev);
 
-       if (de_iir & DE_PIPEA_VBLANK)
-               drm_handle_vblank(dev, 0);
-
-       if (de_iir & DE_PIPEB_VBLANK)
-               drm_handle_vblank(dev, 1);
-
        if (de_iir & DE_POISON)
                DRM_ERROR("Poison interrupt\n");
 
-       if (de_iir & DE_PIPEA_FIFO_UNDERRUN)
-               if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_A, false))
-                       DRM_DEBUG_DRIVER("Pipe A FIFO underrun\n");
+       for_each_pipe(pipe) {
+               if (de_iir & DE_PIPE_VBLANK(pipe))
+                       drm_handle_vblank(dev, pipe);
 
-       if (de_iir & DE_PIPEB_FIFO_UNDERRUN)
-               if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_B, false))
-                       DRM_DEBUG_DRIVER("Pipe B FIFO underrun\n");
+               if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe))
+                       if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
+                               DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n",
+                                                pipe_name(pipe));
 
-       if (de_iir & DE_PLANEA_FLIP_DONE) {
-               intel_prepare_page_flip(dev, 0);
-               intel_finish_page_flip_plane(dev, 0);
-       }
+               if (de_iir & DE_PIPE_CRC_DONE(pipe))
+                       i9xx_pipe_crc_irq_handler(dev, pipe);
 
-       if (de_iir & DE_PLANEB_FLIP_DONE) {
-               intel_prepare_page_flip(dev, 1);
-               intel_finish_page_flip_plane(dev, 1);
+               /* 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);
+               }
        }
 
        /* check event from PCH */
@@ -1351,7 +1690,7 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
 static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int i;
+       enum pipe i;
 
        if (de_iir & DE_ERR_INT_IVB)
                ivb_err_int_handler(dev);
@@ -1362,10 +1701,12 @@ static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
        if (de_iir & DE_GSE_IVB)
                intel_opregion_asle_intr(dev);
 
-       for (i = 0; i < 3; i++) {
-               if (de_iir & (DE_PIPEA_VBLANK_IVB << (5 * i)))
+       for_each_pipe(i) {
+               if (de_iir & (DE_PIPE_VBLANK_IVB(i)))
                        drm_handle_vblank(dev, i);
-               if (de_iir & (DE_PLANEA_FLIP_DONE_IVB << (5 * i))) {
+
+               /* plane/pipes map 1:1 on ilk+ */
+               if (de_iir & DE_PLANE_FLIP_DONE_IVB(i)) {
                        intel_prepare_page_flip(dev, i);
                        intel_finish_page_flip_plane(dev, i);
                }
@@ -1388,7 +1729,6 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        u32 de_iir, gt_iir, de_ier, sde_ier = 0;
        irqreturn_t ret = IRQ_NONE;
-       bool err_int_reenable = false;
 
        atomic_inc(&dev_priv->irq_received);
 
@@ -1412,17 +1752,6 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
                POSTING_READ(SDEIER);
        }
 
-       /* On Haswell, also mask ERR_INT because we don't want to risk
-        * generating "unclaimed register" interrupts from inside the interrupt
-        * handler. */
-       if (IS_HASWELL(dev)) {
-               spin_lock(&dev_priv->irq_lock);
-               err_int_reenable = ~dev_priv->irq_mask & DE_ERR_INT_IVB;
-               if (err_int_reenable)
-                       ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
-               spin_unlock(&dev_priv->irq_lock);
-       }
-
        gt_iir = I915_READ(GTIIR);
        if (gt_iir) {
                if (INTEL_INFO(dev)->gen >= 6)
@@ -1452,13 +1781,6 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
                }
        }
 
-       if (err_int_reenable) {
-               spin_lock(&dev_priv->irq_lock);
-               if (ivb_can_enable_err_int(dev))
-                       ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
-               spin_unlock(&dev_priv->irq_lock);
-       }
-
        I915_WRITE(DEIER, de_ier);
        POSTING_READ(DEIER);
        if (!HAS_PCH_NOP(dev)) {
@@ -1469,6 +1791,117 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
        return ret;
 }
 
+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;
+       irqreturn_t ret = IRQ_NONE;
+       uint32_t tmp = 0;
+       enum pipe pipe;
+
+       atomic_inc(&dev_priv->irq_received);
+
+       master_ctl = I915_READ(GEN8_MASTER_IRQ);
+       master_ctl &= ~GEN8_MASTER_IRQ_CONTROL;
+       if (!master_ctl)
+               return IRQ_NONE;
+
+       I915_WRITE(GEN8_MASTER_IRQ, 0);
+       POSTING_READ(GEN8_MASTER_IRQ);
+
+       ret = gen8_gt_irq_handler(dev, dev_priv, master_ctl);
+
+       if (master_ctl & GEN8_DE_MISC_IRQ) {
+               tmp = I915_READ(GEN8_DE_MISC_IIR);
+               if (tmp & GEN8_DE_MISC_GSE)
+                       intel_opregion_asle_intr(dev);
+               else if (tmp)
+                       DRM_ERROR("Unexpected DE Misc interrupt\n");
+               else
+                       DRM_ERROR("The master control interrupt lied (DE MISC)!\n");
+
+               if (tmp) {
+                       I915_WRITE(GEN8_DE_MISC_IIR, tmp);
+                       ret = IRQ_HANDLED;
+               }
+       }
+
+       if (master_ctl & GEN8_DE_PORT_IRQ) {
+               tmp = I915_READ(GEN8_DE_PORT_IIR);
+               if (tmp & GEN8_AUX_CHANNEL_A)
+                       dp_aux_irq_handler(dev);
+               else if (tmp)
+                       DRM_ERROR("Unexpected DE Port interrupt\n");
+               else
+                       DRM_ERROR("The master control interrupt lied (DE PORT)!\n");
+
+               if (tmp) {
+                       I915_WRITE(GEN8_DE_PORT_IIR, tmp);
+                       ret = IRQ_HANDLED;
+               }
+       }
+
+       for_each_pipe(pipe) {
+               uint32_t pipe_iir;
+
+               if (!(master_ctl & GEN8_DE_PIPE_IRQ(pipe)))
+                       continue;
+
+               pipe_iir = I915_READ(GEN8_DE_PIPE_IIR(pipe));
+               if (pipe_iir & GEN8_PIPE_VBLANK)
+                       drm_handle_vblank(dev, pipe);
+
+               if (pipe_iir & GEN8_PIPE_FLIP_DONE) {
+                       intel_prepare_page_flip(dev, pipe);
+                       intel_finish_page_flip_plane(dev, pipe);
+               }
+
+               if (pipe_iir & GEN8_PIPE_CDCLK_CRC_DONE)
+                       hsw_pipe_crc_irq_handler(dev, pipe);
+
+               if (pipe_iir & GEN8_PIPE_FIFO_UNDERRUN) {
+                       if (intel_set_cpu_fifo_underrun_reporting(dev, pipe,
+                                                                 false))
+                               DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n",
+                                                pipe_name(pipe));
+               }
+
+               if (pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS) {
+                       DRM_ERROR("Fault errors on pipe %c\n: 0x%08x",
+                                 pipe_name(pipe),
+                                 pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS);
+               }
+
+               if (pipe_iir) {
+                       ret = IRQ_HANDLED;
+                       I915_WRITE(GEN8_DE_PIPE_IIR(pipe), pipe_iir);
+               } else
+                       DRM_ERROR("The master control interrupt lied (DE PIPE)!\n");
+       }
+
+       if (!HAS_PCH_NOP(dev) && master_ctl & GEN8_DE_PCH_IRQ) {
+               /*
+                * FIXME(BDW): Assume for now that the new interrupt handling
+                * scheme also closed the SDE interrupt handling race we've seen
+                * on older pch-split platforms. But this needs testing.
+                */
+               u32 pch_iir = I915_READ(SDEIIR);
+
+               cpt_irq_handler(dev, pch_iir);
+
+               if (pch_iir) {
+                       I915_WRITE(SDEIIR, pch_iir);
+                       ret = IRQ_HANDLED;
+               }
+       }
+
+       I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
+       POSTING_READ(GEN8_MASTER_IRQ);
+
+       return ret;
+}
+
 static void i915_error_wake_up(struct drm_i915_private *dev_priv,
                               bool reset_completed)
 {
@@ -1516,7 +1949,7 @@ static void i915_error_work_func(struct work_struct *work)
        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(&dev->primary->kdev->kobj, KOBJ_CHANGE, error_event);
 
        /*
         * Note that there's only one work item which does gpu resets, so we
@@ -1530,7 +1963,7 @@ static void i915_error_work_func(struct work_struct *work)
         */
        if (i915_reset_in_progress(error) && !i915_terminally_wedged(error)) {
                DRM_DEBUG_DRIVER("resetting chip\n");
-               kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE,
+               kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE,
                                   reset_event);
 
                /*
@@ -1557,7 +1990,7 @@ static void i915_error_work_func(struct work_struct *work)
                        smp_mb__before_atomic_inc();
                        atomic_inc(&dev_priv->gpu_error.reset_counter);
 
-                       kobject_uevent_env(&dev->primary->kdev.kobj,
+                       kobject_uevent_env(&dev->primary->kdev->kobj,
                                           KOBJ_CHANGE, reset_done_event);
                } else {
                        atomic_set(&error->reset_counter, I915_WEDGED);
@@ -1787,7 +2220,7 @@ static int ironlake_enable_vblank(struct drm_device *dev, int pipe)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        unsigned long irqflags;
        uint32_t bit = (INTEL_INFO(dev)->gen >= 7) ? DE_PIPE_VBLANK_IVB(pipe) :
-                                                    DE_PIPE_VBLANK_ILK(pipe);
+                                                    DE_PIPE_VBLANK(pipe);
 
        if (!i915_pipe_enabled(dev, pipe))
                return -EINVAL;
@@ -1810,7 +2243,7 @@ static int valleyview_enable_vblank(struct drm_device *dev, int pipe)
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        imr = I915_READ(VLV_IMR);
-       if (pipe == 0)
+       if (pipe == PIPE_A)
                imr &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
        else
                imr &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
@@ -1822,6 +2255,22 @@ static int valleyview_enable_vblank(struct drm_device *dev, int pipe)
        return 0;
 }
 
+static int gen8_enable_vblank(struct drm_device *dev, int pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long irqflags;
+
+       if (!i915_pipe_enabled(dev, pipe))
+               return -EINVAL;
+
+       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       dev_priv->de_irq_mask[pipe] &= ~GEN8_PIPE_VBLANK;
+       I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]);
+       POSTING_READ(GEN8_DE_PIPE_IMR(pipe));
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       return 0;
+}
+
 /* Called from drm generic code, passed 'crtc' which
  * we use as a pipe index
  */
@@ -1845,7 +2294,7 @@ static void ironlake_disable_vblank(struct drm_device *dev, int pipe)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        unsigned long irqflags;
        uint32_t bit = (INTEL_INFO(dev)->gen >= 7) ? DE_PIPE_VBLANK_IVB(pipe) :
-                                                    DE_PIPE_VBLANK_ILK(pipe);
+                                                    DE_PIPE_VBLANK(pipe);
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        ironlake_disable_display_irq(dev_priv, bit);
@@ -1862,7 +2311,7 @@ static void valleyview_disable_vblank(struct drm_device *dev, int pipe)
        i915_disable_pipestat(dev_priv, pipe,
                              PIPE_START_VBLANK_INTERRUPT_ENABLE);
        imr = I915_READ(VLV_IMR);
-       if (pipe == 0)
+       if (pipe == PIPE_A)
                imr |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
        else
                imr |= I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
@@ -1870,6 +2319,21 @@ static void valleyview_disable_vblank(struct drm_device *dev, int pipe)
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
 
+static void gen8_disable_vblank(struct drm_device *dev, int pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long irqflags;
+
+       if (!i915_pipe_enabled(dev, pipe))
+               return;
+
+       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       dev_priv->de_irq_mask[pipe] |= GEN8_PIPE_VBLANK;
+       I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]);
+       POSTING_READ(GEN8_DE_PIPE_IMR(pipe));
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+}
+
 static u32
 ring_last_seqno(struct intel_ring_buffer *ring)
 {
@@ -1965,6 +2429,7 @@ ring_stuck(struct intel_ring_buffer *ring, u32 acthd)
        if (tmp & RING_WAIT) {
                DRM_ERROR("Kicking stuck wait on %s\n",
                          ring->name);
+               i915_handle_error(dev, false);
                I915_WRITE_CTL(ring, tmp);
                return HANGCHECK_KICK;
        }
@@ -1976,6 +2441,7 @@ ring_stuck(struct intel_ring_buffer *ring, u32 acthd)
                case 1:
                        DRM_ERROR("Kicking stuck semaphore on %s\n",
                                  ring->name);
+                       i915_handle_error(dev, false);
                        I915_WRITE_CTL(ring, tmp);
                        return HANGCHECK_KICK;
                case 0:
@@ -2021,12 +2487,21 @@ static void i915_hangcheck_elapsed(unsigned long data)
 
                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. */
-                                       DRM_ERROR("Hangcheck timer elapsed... %s idle\n",
-                                                 ring->name);
-                                       wake_up_all(&ring->irq_queue);
-                                       ring->hangcheck.score += HUNG;
+                                       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);
+                                       }
+                                       /* Safeguard against driver failure */
+                                       ring->hangcheck.score += BUSY;
                                } else
                                        busy = false;
                        } else {
@@ -2049,6 +2524,7 @@ static void i915_hangcheck_elapsed(unsigned long data)
                                                                    acthd);
 
                                switch (ring->hangcheck.action) {
+                               case HANGCHECK_IDLE:
                                case HANGCHECK_WAIT:
                                        break;
                                case HANGCHECK_ACTIVE:
@@ -2064,6 +2540,8 @@ static void i915_hangcheck_elapsed(unsigned long data)
                                }
                        }
                } else {
+                       ring->hangcheck.action = HANGCHECK_ACTIVE;
+
                        /* Gradually reduce the count so that we catch DoS
                         * attempts across multiple batches.
                         */
@@ -2190,6 +2668,53 @@ static void valleyview_irq_preinstall(struct drm_device *dev)
        POSTING_READ(VLV_IER);
 }
 
+static void gen8_irq_preinstall(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int pipe;
+
+       atomic_set(&dev_priv->irq_received, 0);
+
+       I915_WRITE(GEN8_MASTER_IRQ, 0);
+       POSTING_READ(GEN8_MASTER_IRQ);
+
+       /* 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);
+
+       for_each_pipe(pipe) {
+               GEN8_IRQ_INIT_NDX(DE_PIPE, pipe);
+       }
+
+       GEN8_IRQ_INIT(DE_PORT);
+       GEN8_IRQ_INIT(DE_MISC);
+       GEN8_IRQ_INIT(PCU);
+#undef GEN8_IRQ_INIT
+#undef GEN8_IRQ_INIT_NDX
+
+       POSTING_READ(GEN8_PCU_IIR);
+}
+
 static void ibx_hpd_irq_setup(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -2254,10 +2779,10 @@ static void gen5_gt_irq_postinstall(struct drm_device *dev)
        pm_irqs = gt_irqs = 0;
 
        dev_priv->gt_irq_mask = ~0;
-       if (HAS_L3_GPU_CACHE(dev)) {
+       if (HAS_L3_DPF(dev)) {
                /* L3 parity interrupt is always unmasked. */
-               dev_priv->gt_irq_mask = ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
-               gt_irqs |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
+               dev_priv->gt_irq_mask = ~GT_PARITY_ERROR(dev);
+               gt_irqs |= GT_PARITY_ERROR(dev);
        }
 
        gt_irqs |= GT_RENDER_USER_INTERRUPT;
@@ -2306,8 +2831,10 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
        } else {
                display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
                                DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE |
-                               DE_AUX_CHANNEL_A | DE_PIPEB_FIFO_UNDERRUN |
-                               DE_PIPEA_FIFO_UNDERRUN | DE_POISON);
+                               DE_AUX_CHANNEL_A |
+                               DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN |
+                               DE_PIPEB_CRC_DONE | DE_PIPEA_CRC_DONE |
+                               DE_POISON);
                extra_mask = DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT;
        }
 
@@ -2341,7 +2868,8 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        u32 enable_mask;
-       u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV;
+       u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV |
+               PIPE_CRC_DONE_ENABLE;
        unsigned long irqflags;
 
        enable_mask = I915_DISPLAY_PORT_INTERRUPT;
@@ -2371,9 +2899,9 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
        /* Interrupt setup is already guaranteed to be single-threaded, this is
         * just to make the assert_spin_locked check happy. */
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       i915_enable_pipestat(dev_priv, 0, pipestat_enable);
-       i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE);
-       i915_enable_pipestat(dev_priv, 1, pipestat_enable);
+       i915_enable_pipestat(dev_priv, PIPE_A, pipestat_enable);
+       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_EVENT_ENABLE);
+       i915_enable_pipestat(dev_priv, PIPE_B, pipestat_enable);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
        I915_WRITE(VLV_IIR, 0xffffffff);
@@ -2392,6 +2920,117 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
        return 0;
 }
 
+static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
+{
+       int i;
+
+       /* These are interrupts we'll toggle with the ring mask register */
+       uint32_t gt_interrupts[] = {
+               GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
+                       GT_RENDER_L3_PARITY_ERROR_INTERRUPT |
+                       GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT,
+               GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT |
+                       GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT,
+               0,
+               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));
+}
+
+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 |
+               GEN8_PIPE_CDCLK_CRC_DONE |
+               GEN8_PIPE_FIFO_UNDERRUN |
+               GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
+       uint32_t de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK;
+       int pipe;
+       dev_priv->de_irq_mask[PIPE_A] = ~de_pipe_masked;
+       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));
+
+       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);
+}
+
+static int gen8_irq_postinstall(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       gen8_gt_irq_postinstall(dev_priv);
+       gen8_de_irq_postinstall(dev_priv);
+
+       ibx_irq_postinstall(dev);
+
+       I915_WRITE(GEN8_MASTER_IRQ, DE_MASTER_IRQ_CONTROL);
+       POSTING_READ(GEN8_MASTER_IRQ);
+
+       return 0;
+}
+
+static void gen8_irq_uninstall(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int pipe;
+
+       if (!dev_priv)
+               return;
+
+       atomic_set(&dev_priv->irq_received, 0);
+
+       I915_WRITE(GEN8_MASTER_IRQ, 0);
+
+#define GEN8_IRQ_FINI_NDX(type, which) do { \
+               I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \
+               I915_WRITE(GEN8_##type##_IER(which), 0); \
+               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); \
+       } while (0)
+
+       GEN8_IRQ_FINI_NDX(GT, 0);
+       GEN8_IRQ_FINI_NDX(GT, 1);
+       GEN8_IRQ_FINI_NDX(GT, 2);
+       GEN8_IRQ_FINI_NDX(GT, 3);
+
+       for_each_pipe(pipe) {
+               GEN8_IRQ_FINI_NDX(DE_PIPE, pipe);
+       }
+
+       GEN8_IRQ_FINI(DE_PORT);
+       GEN8_IRQ_FINI(DE_MISC);
+       GEN8_IRQ_FINI(PCU);
+#undef GEN8_IRQ_FINI
+#undef GEN8_IRQ_FINI_NDX
+
+       POSTING_READ(GEN8_PCU_IIR);
+}
+
 static void valleyview_irq_uninstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -2464,6 +3103,7 @@ static void i8xx_irq_preinstall(struct drm_device * dev)
 static int i8xx_irq_postinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       unsigned long irqflags;
 
        I915_WRITE16(EMR,
                     ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH));
@@ -2484,6 +3124,13 @@ static int i8xx_irq_postinstall(struct drm_device *dev)
                     I915_USER_INTERRUPT);
        POSTING_READ16(IER);
 
+       /* Interrupt setup is already guaranteed to be single-threaded, this is
+        * just to make the assert_spin_locked check happy. */
+       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_ENABLE);
+       i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_ENABLE);
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
        return 0;
 }
 
@@ -2570,13 +3217,14 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
                if (iir & I915_USER_INTERRUPT)
                        notify_ring(dev, &dev_priv->ring[RCS]);
 
-               if (pipe_stats[0] & PIPE_VBLANK_INTERRUPT_STATUS &&
-                   i8xx_handle_vblank(dev, 0, iir))
-                       flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(0);
+               for_each_pipe(pipe) {
+                       if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS &&
+                           i8xx_handle_vblank(dev, pipe, iir))
+                               flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(pipe);
 
-               if (pipe_stats[1] & PIPE_VBLANK_INTERRUPT_STATUS &&
-                   i8xx_handle_vblank(dev, 1, iir))
-                       flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(1);
+                       if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
+                               i9xx_pipe_crc_irq_handler(dev, pipe);
+               }
 
                iir = new_iir;
        }
@@ -2623,6 +3271,7 @@ static int i915_irq_postinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        u32 enable_mask;
+       unsigned long irqflags;
 
        I915_WRITE(EMR, ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH));
 
@@ -2658,6 +3307,13 @@ static int i915_irq_postinstall(struct drm_device *dev)
 
        i915_enable_asle_pipestat(dev);
 
+       /* Interrupt setup is already guaranteed to be single-threaded, this is
+        * just to make the assert_spin_locked check happy. */
+       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_ENABLE);
+       i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_ENABLE);
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
        return 0;
 }
 
@@ -2769,6 +3425,9 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 
                        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);
                }
 
                if (blc_event || (iir & I915_ASLE_INTERRUPT))
@@ -2867,7 +3526,9 @@ static int i965_irq_postinstall(struct drm_device *dev)
        /* Interrupt setup is already guaranteed to be single-threaded, this is
         * just to make the assert_spin_locked check happy. */
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE);
+       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_EVENT_ENABLE);
+       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_ENABLE);
+       i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_ENABLE);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
        /*
@@ -3013,6 +3674,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 
                        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);
                }
 
 
@@ -3122,18 +3786,21 @@ void intel_irq_init(struct drm_device *dev)
 
        pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
 
-       dev->driver->get_vblank_counter = i915_get_vblank_counter;
-       dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
-       if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
+       if (IS_GEN2(dev)) {
+               dev->max_vblank_count = 0;
+               dev->driver->get_vblank_counter = i8xx_get_vblank_counter;
+       } else if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
                dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
                dev->driver->get_vblank_counter = gm45_get_vblank_counter;
+       } else {
+               dev->driver->get_vblank_counter = i915_get_vblank_counter;
+               dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
        }
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
+       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp;
-       else
-               dev->driver->get_vblank_timestamp = NULL;
-       dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;
+               dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;
+       }
 
        if (IS_VALLEYVIEW(dev)) {
                dev->driver->irq_handler = valleyview_irq_handler;
@@ -3143,6 +3810,14 @@ void intel_irq_init(struct drm_device *dev)
                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_GEN8(dev)) {
+               dev->driver->irq_handler = gen8_irq_handler;
+               dev->driver->irq_preinstall = gen8_irq_preinstall;
+               dev->driver->irq_postinstall = gen8_irq_postinstall;
+               dev->driver->irq_uninstall = gen8_irq_uninstall;
+               dev->driver->enable_vblank = gen8_enable_vblank;
+               dev->driver->disable_vblank = gen8_disable_vblank;
+               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;