drm/i915: split irq handling into per-chipset functions
[pandora-kernel.git] / drivers / gpu / drm / i915 / i915_irq.c
index 8a9e08b..d967e17 100644 (file)
@@ -85,21 +85,11 @@ ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
        }
 }
 
-static inline u32
-i915_pipestat(int pipe)
-{
-       if (pipe == 0)
-               return PIPEASTAT;
-       if (pipe == 1)
-               return PIPEBSTAT;
-       BUG();
-}
-
 void
 i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
 {
        if ((dev_priv->pipestat[pipe] & mask) != mask) {
-               u32 reg = i915_pipestat(pipe);
+               u32 reg = PIPESTAT(pipe);
 
                dev_priv->pipestat[pipe] |= mask;
                /* Enable the interrupt, clear any pending status */
@@ -112,7 +102,7 @@ void
 i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
 {
        if ((dev_priv->pipestat[pipe] & mask) != 0) {
-               u32 reg = i915_pipestat(pipe);
+               u32 reg = PIPESTAT(pipe);
 
                dev_priv->pipestat[pipe] &= ~mask;
                I915_WRITE(reg, dev_priv->pipestat[pipe]);
@@ -171,12 +161,12 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
 
        if (!i915_pipe_enabled(dev, pipe)) {
                DRM_DEBUG_DRIVER("trying to get vblank count for disabled "
-                               "pipe %d\n", pipe);
+                               "pipe %c\n", pipe_name(pipe));
                return 0;
        }
 
-       high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
-       low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
+       high_frame = PIPEFRAME(pipe);
+       low_frame = PIPEFRAMEPIXEL(pipe);
 
        /*
         * High & low register fields aren't synchronized, so make sure
@@ -197,11 +187,11 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
 u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       int reg = pipe ? PIPEB_FRMCOUNT_GM45 : PIPEA_FRMCOUNT_GM45;
+       int reg = PIPE_FRMCOUNT_GM45(pipe);
 
        if (!i915_pipe_enabled(dev, pipe)) {
                DRM_DEBUG_DRIVER("trying to get vblank count for disabled "
-                                       "pipe %d\n", pipe);
+                                "pipe %c\n", pipe_name(pipe));
                return 0;
        }
 
@@ -219,7 +209,7 @@ int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
 
        if (!i915_pipe_enabled(dev, pipe)) {
                DRM_DEBUG_DRIVER("trying to get scanoutpos for disabled "
-                                       "pipe %d\n", pipe);
+                                "pipe %c\n", pipe_name(pipe));
                return 0;
        }
 
@@ -367,7 +357,7 @@ static void notify_ring(struct drm_device *dev,
                return;
 
        seqno = ring->get_seqno(ring);
-       trace_i915_gem_request_complete(dev, seqno);
+       trace_i915_gem_request_complete(ring, seqno);
 
        ring->irq_seqno = seqno;
        wake_up_all(&ring->irq_queue);
@@ -377,22 +367,30 @@ static void notify_ring(struct drm_device *dev,
                  jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
 }
 
-static void gen6_pm_irq_handler(struct drm_device *dev)
+static void gen6_pm_rps_work(struct work_struct *work)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
+                                                   rps_work);
        u8 new_delay = dev_priv->cur_delay;
-       u32 pm_iir;
+       u32 pm_iir, pm_imr;
+
+       spin_lock_irq(&dev_priv->rps_lock);
+       pm_iir = dev_priv->pm_iir;
+       dev_priv->pm_iir = 0;
+       pm_imr = I915_READ(GEN6_PMIMR);
+       spin_unlock_irq(&dev_priv->rps_lock);
 
-       pm_iir = I915_READ(GEN6_PMIIR);
        if (!pm_iir)
                return;
 
+       mutex_lock(&dev_priv->dev->struct_mutex);
        if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
                if (dev_priv->cur_delay != dev_priv->max_delay)
                        new_delay = dev_priv->cur_delay + 1;
                if (new_delay > dev_priv->max_delay)
                        new_delay = dev_priv->max_delay;
        } else if (pm_iir & (GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT)) {
+               gen6_gt_force_wake_get(dev_priv);
                if (dev_priv->cur_delay != dev_priv->min_delay)
                        new_delay = dev_priv->cur_delay - 1;
                if (new_delay < dev_priv->min_delay) {
@@ -406,19 +404,26 @@ static void gen6_pm_irq_handler(struct drm_device *dev)
                        I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
                                   I915_READ(GEN6_RP_INTERRUPT_LIMITS) & ~0x3f0000);
                }
-
+               gen6_gt_force_wake_put(dev_priv);
        }
 
-       gen6_set_rps(dev, new_delay);
+       gen6_set_rps(dev_priv->dev, new_delay);
        dev_priv->cur_delay = new_delay;
 
-       I915_WRITE(GEN6_PMIIR, pm_iir);
+       /*
+        * rps_lock not held here because clearing is non-destructive. There is
+        * an *extremely* unlikely race with gen6_rps_enable() that is prevented
+        * by holding struct_mutex for the duration of the write.
+        */
+       I915_WRITE(GEN6_PMIMR, pm_imr & ~pm_iir);
+       mutex_unlock(&dev_priv->dev->struct_mutex);
 }
 
 static void pch_irq_handler(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        u32 pch_iir;
+       int pipe;
 
        pch_iir = I915_READ(SDEIIR);
 
@@ -439,13 +444,11 @@ static void pch_irq_handler(struct drm_device *dev)
        if (pch_iir & SDE_POISON)
                DRM_ERROR("PCH poison interrupt\n");
 
-       if (pch_iir & SDE_FDI_MASK) {
-               u32 fdia, fdib;
-
-               fdia = I915_READ(FDI_RXA_IIR);
-               fdib = I915_READ(FDI_RXB_IIR);
-               DRM_DEBUG_DRIVER("PCH FDI RX interrupt; FDI RXA IIR: 0x%08x, FDI RXB IIR: 0x%08x\n", fdia, fdib);
-       }
+       if (pch_iir & SDE_FDI_MASK)
+               for_each_pipe(pipe)
+                       DRM_DEBUG_DRIVER("  pipe %c FDI IIR: 0x%08x\n",
+                                        pipe_name(pipe),
+                                        I915_READ(FDI_RX_IIR(pipe)));
 
        if (pch_iir & (SDE_TRANSB_CRC_DONE | SDE_TRANSA_CRC_DONE))
                DRM_DEBUG_DRIVER("PCH transcoder CRC done interrupt\n");
@@ -459,8 +462,9 @@ static void pch_irq_handler(struct drm_device *dev)
                DRM_DEBUG_DRIVER("PCH transcoder A underrun interrupt\n");
 }
 
-static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
+irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS)
 {
+       struct drm_device *dev = (struct drm_device *) arg;
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        int ret = IRQ_NONE;
        u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir;
@@ -468,6 +472,8 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
        struct drm_i915_master_private *master_priv;
        u32 bsd_usr_interrupt = GT_BSD_USER_INTERRUPT;
 
+       atomic_inc(&dev_priv->irq_received);
+
        if (IS_GEN6(dev))
                bsd_usr_interrupt = GT_GEN6_BSD_USER_INTERRUPT;
 
@@ -537,13 +543,30 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
                i915_handle_rps_change(dev);
        }
 
-       if (IS_GEN6(dev))
-               gen6_pm_irq_handler(dev);
+       if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS) {
+               /*
+                * IIR bits should never already be set because IMR should
+                * prevent an interrupt from being shown in IIR. The warning
+                * displays a case where we've unsafely cleared
+                * dev_priv->pm_iir. Although missing an interrupt of the same
+                * type is not a problem, it displays a problem in the logic.
+                *
+                * The mask bit in IMR is cleared by rps_work.
+                */
+               unsigned long flags;
+               spin_lock_irqsave(&dev_priv->rps_lock, flags);
+               WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n");
+               I915_WRITE(GEN6_PMIMR, pm_iir);
+               dev_priv->pm_iir |= pm_iir;
+               spin_unlock_irqrestore(&dev_priv->rps_lock, flags);
+               queue_work(dev_priv->wq, &dev_priv->rps_work);
+       }
 
        /* should clear PCH hotplug event before clear CPU irq */
        I915_WRITE(SDEIIR, pch_iir);
        I915_WRITE(GTIIR, gt_iir);
        I915_WRITE(DEIIR, de_iir);
+       I915_WRITE(GEN6_PMIIR, pm_iir);
 
 done:
        I915_WRITE(DEIER, de_ier);
@@ -650,9 +673,14 @@ static void
 i915_error_state_free(struct drm_device *dev,
                      struct drm_i915_error_state *error)
 {
-       i915_error_object_free(error->batchbuffer[0]);
-       i915_error_object_free(error->batchbuffer[1]);
-       i915_error_object_free(error->ringbuffer);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(error->batchbuffer); i++)
+               i915_error_object_free(error->batchbuffer[i]);
+
+       for (i = 0; i < ARRAY_SIZE(error->ringbuffer); i++)
+               i915_error_object_free(error->ringbuffer[i]);
+
        kfree(error->active_bo);
        kfree(error->overlay);
        kfree(error);
@@ -682,7 +710,7 @@ static u32 capture_bo_list(struct drm_i915_error_buffer *err,
                err->dirty = obj->dirty;
                err->purgeable = obj->madv != I915_MADV_WILLNEED;
                err->ring = obj->ring ? obj->ring->id : 0;
-               err->agp_type = obj->agp_type == AGP_USER_CACHED_MEMORY;
+               err->cache_level = obj->cache_level;
 
                if (++i == count)
                        break;
@@ -767,7 +795,7 @@ static void i915_capture_error_state(struct drm_device *dev)
        struct drm_i915_gem_object *obj;
        struct drm_i915_error_state *error;
        unsigned long flags;
-       int i;
+       int i, pipe;
 
        spin_lock_irqsave(&dev_priv->error_lock, flags);
        error = dev_priv->first_error;
@@ -775,19 +803,21 @@ static void i915_capture_error_state(struct drm_device *dev)
        if (error)
                return;
 
+       /* Account for pipe specific data like PIPE*STAT */
        error = kmalloc(sizeof(*error), GFP_ATOMIC);
        if (!error) {
                DRM_DEBUG_DRIVER("out of memory, not capturing error state\n");
                return;
        }
 
-       DRM_DEBUG_DRIVER("generating error event\n");
+       DRM_INFO("capturing error event; look for more information in /debug/dri/%d/i915_error_state\n",
+                dev->primary->index);
 
        error->seqno = dev_priv->ring[RCS].get_seqno(&dev_priv->ring[RCS]);
        error->eir = I915_READ(EIR);
        error->pgtbl_er = I915_READ(PGTBL_ER);
-       error->pipeastat = I915_READ(PIPEASTAT);
-       error->pipebstat = I915_READ(PIPEBSTAT);
+       for_each_pipe(pipe)
+               error->pipestat[pipe] = I915_READ(PIPESTAT(pipe));
        error->instpm = I915_READ(INSTPM);
        error->error = 0;
        if (INTEL_INFO(dev)->gen >= 6) {
@@ -826,15 +856,16 @@ static void i915_capture_error_state(struct drm_device *dev)
        }
        i915_gem_record_fences(dev, error);
 
-       /* Record the active batchbuffers */
-       for (i = 0; i < I915_NUM_RINGS; i++)
+       /* Record the active batch and ring buffers */
+       for (i = 0; i < I915_NUM_RINGS; i++) {
                error->batchbuffer[i] =
                        i915_error_first_batchbuffer(dev_priv,
                                                     &dev_priv->ring[i]);
 
-       /* Record the ringbuffer */
-       error->ringbuffer = i915_error_object_create(dev_priv,
-                                                    dev_priv->ring[RCS].obj);
+               error->ringbuffer[i] =
+                       i915_error_object_create(dev_priv,
+                                                dev_priv->ring[i].obj);
+       }
 
        /* Record buffers on the active and pinned lists. */
        error->active_bo = NULL;
@@ -907,6 +938,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 eir = I915_READ(EIR);
+       int pipe;
 
        if (!eir)
                return;
@@ -955,14 +987,10 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
        }
 
        if (eir & I915_ERROR_MEMORY_REFRESH) {
-               u32 pipea_stats = I915_READ(PIPEASTAT);
-               u32 pipeb_stats = I915_READ(PIPEBSTAT);
-
-               printk(KERN_ERR "memory refresh error\n");
-               printk(KERN_ERR "PIPEASTAT: 0x%08x\n",
-                      pipea_stats);
-               printk(KERN_ERR "PIPEBSTAT: 0x%08x\n",
-                      pipeb_stats);
+               printk(KERN_ERR "memory refresh error:\n");
+               for_each_pipe(pipe)
+                       printk(KERN_ERR "pipe %c stat: 0x%08x\n",
+                              pipe_name(pipe), I915_READ(PIPESTAT(pipe)));
                /* pipestat has already been acked */
        }
        if (eir & I915_ERROR_INSTRUCTION) {
@@ -1076,10 +1104,10 @@ static void i915_pageflip_stall_check(struct drm_device *dev, int pipe)
        /* Potential stall - if we see that the flip has happened, assume a missed interrupt */
        obj = work->pending_flip_obj;
        if (INTEL_INFO(dev)->gen >= 4) {
-               int dspsurf = intel_crtc->plane == 0 ? DSPASURF : DSPBSURF;
+               int dspsurf = DSPSURF(intel_crtc->plane);
                stall_detected = I915_READ(dspsurf) == obj->gtt_offset;
        } else {
-               int dspaddr = intel_crtc->plane == 0 ? DSPAADDR : DSPBADDR;
+               int dspaddr = DSPADDR(intel_crtc->plane);
                stall_detected = I915_READ(dspaddr) == (obj->gtt_offset +
                                                        crtc->y * crtc->fb->pitch +
                                                        crtc->x * crtc->fb->bits_per_pixel/8);
@@ -1099,18 +1127,16 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        struct drm_i915_master_private *master_priv;
        u32 iir, new_iir;
-       u32 pipea_stats, pipeb_stats;
+       u32 pipe_stats[I915_MAX_PIPES];
        u32 vblank_status;
        int vblank = 0;
        unsigned long irqflags;
        int irq_received;
-       int ret = IRQ_NONE;
+       int ret = IRQ_NONE, pipe;
+       bool blc_event = false;
 
        atomic_inc(&dev_priv->irq_received);
 
-       if (HAS_PCH_SPLIT(dev))
-               return ironlake_irq_handler(dev);
-
        iir = I915_READ(IIR);
 
        if (INTEL_INFO(dev)->gen >= 4)
@@ -1127,27 +1153,23 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
                 * interrupts (for non-MSI).
                 */
                spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-               pipea_stats = I915_READ(PIPEASTAT);
-               pipeb_stats = I915_READ(PIPEBSTAT);
-
                if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
                        i915_handle_error(dev, false);
 
-               /*
-                * Clear the PIPE(A|B)STAT regs before the IIR
-                */
-               if (pipea_stats & 0x8000ffff) {
-                       if (pipea_stats &  PIPE_FIFO_UNDERRUN_STATUS)
-                               DRM_DEBUG_DRIVER("pipe a underrun\n");
-                       I915_WRITE(PIPEASTAT, pipea_stats);
-                       irq_received = 1;
-               }
-
-               if (pipeb_stats & 0x8000ffff) {
-                       if (pipeb_stats &  PIPE_FIFO_UNDERRUN_STATUS)
-                               DRM_DEBUG_DRIVER("pipe b underrun\n");
-                       I915_WRITE(PIPEBSTAT, pipeb_stats);
-                       irq_received = 1;
+               for_each_pipe(pipe) {
+                       int reg = PIPESTAT(pipe);
+                       pipe_stats[pipe] = I915_READ(reg);
+
+                       /*
+                        * Clear the PIPE*STAT regs before the IIR
+                        */
+                       if (pipe_stats[pipe] & 0x8000ffff) {
+                               if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
+                                       DRM_DEBUG_DRIVER("pipe %c underrun\n",
+                                                        pipe_name(pipe));
+                               I915_WRITE(reg, pipe_stats[pipe]);
+                               irq_received = 1;
+                       }
                }
                spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
@@ -1198,27 +1220,22 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
                                intel_finish_page_flip_plane(dev, 1);
                }
 
-               if (pipea_stats & vblank_status &&
-                   drm_handle_vblank(dev, 0)) {
-                       vblank++;
-                       if (!dev_priv->flip_pending_is_done) {
-                               i915_pageflip_stall_check(dev, 0);
-                               intel_finish_page_flip(dev, 0);
+               for_each_pipe(pipe) {
+                       if (pipe_stats[pipe] & vblank_status &&
+                           drm_handle_vblank(dev, pipe)) {
+                               vblank++;
+                               if (!dev_priv->flip_pending_is_done) {
+                                       i915_pageflip_stall_check(dev, pipe);
+                                       intel_finish_page_flip(dev, pipe);
+                               }
                        }
-               }
 
-               if (pipeb_stats & vblank_status &&
-                   drm_handle_vblank(dev, 1)) {
-                       vblank++;
-                       if (!dev_priv->flip_pending_is_done) {
-                               i915_pageflip_stall_check(dev, 1);
-                               intel_finish_page_flip(dev, 1);
-                       }
+                       if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
+                               blc_event = true;
                }
 
-               if ((pipea_stats & PIPE_LEGACY_BLC_EVENT_STATUS) ||
-                   (pipeb_stats & PIPE_LEGACY_BLC_EVENT_STATUS) ||
-                   (iir & I915_ASLE_INTERRUPT))
+
+               if (blc_event || (iir & I915_ASLE_INTERRUPT))
                        intel_opregion_asle_intr(dev);
 
                /* With MSI, interrupts are only generated when iir
@@ -1268,16 +1285,6 @@ static int i915_emit_irq(struct drm_device * dev)
        return dev_priv->counter;
 }
 
-void i915_trace_irq_get(struct drm_device *dev, u32 seqno)
-{
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       struct intel_ring_buffer *ring = LP_RING(dev_priv);
-
-       if (dev_priv->trace_irq_seqno == 0 &&
-           ring->irq_get(ring))
-               dev_priv->trace_irq_seqno = seqno;
-}
-
 static int i915_wait_irq(struct drm_device * dev, int irq_nr)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -1377,7 +1384,12 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
        else
                i915_enable_pipestat(dev_priv, pipe,
                                     PIPE_VBLANK_INTERRUPT_ENABLE);
+
+       /* maintain vblank delivery even in deep C-states */
+       if (dev_priv->info->gen == 3)
+               I915_WRITE(INSTPM, INSTPM_AGPBUSY_DIS << 16);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
        return 0;
 }
 
@@ -1390,6 +1402,10 @@ void i915_disable_vblank(struct drm_device *dev, int pipe)
        unsigned long irqflags;
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       if (dev_priv->info->gen == 3)
+               I915_WRITE(INSTPM,
+                          INSTPM_AGPBUSY_DIS << 16 | INSTPM_AGPBUSY_DIS);
+
        if (HAS_PCH_SPLIT(dev))
                ironlake_disable_display_irq(dev_priv, (pipe == 0) ?
                                             DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
@@ -1400,16 +1416,6 @@ void i915_disable_vblank(struct drm_device *dev, int pipe)
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
 
-void i915_enable_interrupt (struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (!HAS_PCH_SPLIT(dev))
-               intel_opregion_enable_asle(dev);
-       dev_priv->irq_enabled = 1;
-}
-
-
 /* Set the vblank monitor pipe
  */
 int i915_vblank_pipe_set(struct drm_device *dev, void *data,
@@ -1587,10 +1593,15 @@ repeat:
 
 /* drm_dma.h hooks
 */
-static void ironlake_irq_preinstall(struct drm_device *dev)
+void ironlake_irq_preinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 
+       atomic_set(&dev_priv->irq_received, 0);
+
+       INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
+       INIT_WORK(&dev_priv->error_work, i915_error_work_func);
+
        I915_WRITE(HWSTAM, 0xeffe);
 
        /* XXX hotplug from PCH */
@@ -1610,7 +1621,7 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
        POSTING_READ(SDEIER);
 }
 
-static int ironlake_irq_postinstall(struct drm_device *dev)
+int ironlake_irq_postinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        /* enable kind of interrupts always enabled */
@@ -1619,6 +1630,13 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
        u32 render_irqs;
        u32 hotplug_mask;
 
+       DRM_INIT_WAITQUEUE(&dev_priv->ring[RCS].irq_queue);
+       if (HAS_BSD(dev))
+               DRM_INIT_WAITQUEUE(&dev_priv->ring[VCS].irq_queue);
+       if (HAS_BLT(dev))
+               DRM_INIT_WAITQUEUE(&dev_priv->ring[BCS].irq_queue);
+
+       dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
        dev_priv->irq_mask = ~display_mask;
 
        /* should always can generate irq */
@@ -1646,12 +1664,16 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
        POSTING_READ(GTIER);
 
        if (HAS_PCH_CPT(dev)) {
-               hotplug_mask = SDE_CRT_HOTPLUG_CPT | SDE_PORTB_HOTPLUG_CPT  |
-                              SDE_PORTC_HOTPLUG_CPT | SDE_PORTD_HOTPLUG_CPT ;
+               hotplug_mask = (SDE_CRT_HOTPLUG_CPT |
+                               SDE_PORTB_HOTPLUG_CPT |
+                               SDE_PORTC_HOTPLUG_CPT |
+                               SDE_PORTD_HOTPLUG_CPT);
        } else {
-               hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG |
-                              SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG;
-               hotplug_mask |= SDE_AUX_MASK;
+               hotplug_mask = (SDE_CRT_HOTPLUG |
+                               SDE_PORTB_HOTPLUG |
+                               SDE_PORTC_HOTPLUG |
+                               SDE_PORTD_HOTPLUG |
+                               SDE_AUX_MASK);
        }
 
        dev_priv->pch_irq_mask = ~hotplug_mask;
@@ -1674,16 +1696,13 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
 void i915_driver_irq_preinstall(struct drm_device * dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       int pipe;
 
        atomic_set(&dev_priv->irq_received, 0);
 
        INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
        INIT_WORK(&dev_priv->error_work, i915_error_work_func);
-
-       if (HAS_PCH_SPLIT(dev)) {
-               ironlake_irq_preinstall(dev);
-               return;
-       }
+       INIT_WORK(&dev_priv->rps_work, gen6_pm_rps_work);
 
        if (I915_HAS_HOTPLUG(dev)) {
                I915_WRITE(PORT_HOTPLUG_EN, 0);
@@ -1691,8 +1710,8 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
        }
 
        I915_WRITE(HWSTAM, 0xeffe);
-       I915_WRITE(PIPEASTAT, 0);
-       I915_WRITE(PIPEBSTAT, 0);
+       for_each_pipe(pipe)
+               I915_WRITE(PIPESTAT(pipe), 0);
        I915_WRITE(IMR, 0xffffffff);
        I915_WRITE(IER, 0x0);
        POSTING_READ(IER);
@@ -1708,17 +1727,8 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
        u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR;
        u32 error_mask;
 
-       DRM_INIT_WAITQUEUE(&dev_priv->ring[RCS].irq_queue);
-       if (HAS_BSD(dev))
-               DRM_INIT_WAITQUEUE(&dev_priv->ring[VCS].irq_queue);
-       if (HAS_BLT(dev))
-               DRM_INIT_WAITQUEUE(&dev_priv->ring[BCS].irq_queue);
-
        dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
 
-       if (HAS_PCH_SPLIT(dev))
-               return ironlake_irq_postinstall(dev);
-
        /* Unmask the interrupts that we always want on. */
        dev_priv->irq_mask = ~I915_INTERRUPT_ENABLE_FIX;
 
@@ -1787,9 +1797,15 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
        return 0;
 }
 
-static void ironlake_irq_uninstall(struct drm_device *dev)
+void ironlake_irq_uninstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+       if (!dev_priv)
+               return;
+
+       dev_priv->vblank_pipe = 0;
+
        I915_WRITE(HWSTAM, 0xffffffff);
 
        I915_WRITE(DEIMR, 0xffffffff);
@@ -1804,29 +1820,26 @@ static void ironlake_irq_uninstall(struct drm_device *dev)
 void i915_driver_irq_uninstall(struct drm_device * dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       int pipe;
 
        if (!dev_priv)
                return;
 
        dev_priv->vblank_pipe = 0;
 
-       if (HAS_PCH_SPLIT(dev)) {
-               ironlake_irq_uninstall(dev);
-               return;
-       }
-
        if (I915_HAS_HOTPLUG(dev)) {
                I915_WRITE(PORT_HOTPLUG_EN, 0);
                I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
        }
 
        I915_WRITE(HWSTAM, 0xffffffff);
-       I915_WRITE(PIPEASTAT, 0);
-       I915_WRITE(PIPEBSTAT, 0);
+       for_each_pipe(pipe)
+               I915_WRITE(PIPESTAT(pipe), 0);
        I915_WRITE(IMR, 0xffffffff);
        I915_WRITE(IER, 0x0);
 
-       I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff);
-       I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff);
+       for_each_pipe(pipe)
+               I915_WRITE(PIPESTAT(pipe),
+                          I915_READ(PIPESTAT(pipe)) & 0x8000ffff);
        I915_WRITE(IIR, I915_READ(IIR));
 }