drm/i915/vlv: WA to fix Voltage not getting dropped to Vmin when Gfx is power gated.
[deliverable/linux.git] / drivers / gpu / drm / i915 / i915_irq.c
index 74918e7afeb5c1b27020ffc4bcf9e470fd6b38c0..56edff3bbbb9177784da4249a4daa76133a89a98 100644 (file)
@@ -62,7 +62,7 @@ static const u32 hpd_mask_i915[] = {
        [HPD_PORT_D] = PORTD_HOTPLUG_INT_EN
 };
 
-static const u32 hpd_status_gen4[] = {
+static const u32 hpd_status_g4x[] = {
        [HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
        [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_G4X,
        [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_G4X,
@@ -232,6 +232,18 @@ static bool cpt_can_enable_serr_int(struct drm_device *dev)
        return true;
 }
 
+static void i9xx_clear_fifo_underrun(struct drm_device *dev, enum pipe pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 reg = PIPESTAT(pipe);
+       u32 pipestat = I915_READ(reg) & 0x7fff0000;
+
+       assert_spin_locked(&dev_priv->irq_lock);
+
+       I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
+       POSTING_READ(reg);
+}
+
 static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev,
                                                 enum pipe pipe, bool enable)
 {
@@ -393,7 +405,9 @@ bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
 
        intel_crtc->cpu_fifo_underrun_disabled = !enable;
 
-       if (IS_GEN5(dev) || IS_GEN6(dev))
+       if (enable && (INTEL_INFO(dev)->gen < 5 || IS_VALLEYVIEW(dev)))
+               i9xx_clear_fifo_underrun(dev, pipe);
+       else if (IS_GEN5(dev) || IS_GEN6(dev))
                ironlake_set_fifo_underrun_reporting(dev, pipe, enable);
        else if (IS_GEN7(dev))
                ivybridge_set_fifo_underrun_reporting(dev, pipe, enable);
@@ -621,36 +635,15 @@ static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
 #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)
+static bool ilk_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) {
+       if (INTEL_INFO(dev)->gen < 7) {
                status = pipe == PIPE_A ?
                        DE_PIPEA_VBLANK :
                        DE_PIPEB_VBLANK;
-
-               reg = DEISR;
        } else {
                switch (pipe) {
                default:
@@ -664,18 +657,14 @@ static bool intel_pipe_in_vblank_locked(struct drm_device *dev, enum pipe pipe)
                        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;
+       return __raw_i915_read32(dev_priv, DEISR) & status;
 }
 
 static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
-                            int *vpos, int *hpos, ktime_t *stime, ktime_t *etime)
+                                   unsigned int flags, int *vpos, int *hpos,
+                                   ktime_t *stime, ktime_t *etime)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
@@ -698,6 +687,12 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
        vbl_start = mode->crtc_vblank_start;
        vbl_end = mode->crtc_vblank_end;
 
+       if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+               vbl_start = DIV_ROUND_UP(vbl_start, 2);
+               vbl_end /= 2;
+               vtotal /= 2;
+       }
+
        ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
 
        /*
@@ -722,17 +717,42 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
                else
                        position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
 
-               /*
-                * 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 = intel_pipe_in_vblank_locked(dev, pipe);
-               if ((in_vbl && position == vbl_start - 1) ||
-                   (!in_vbl && position == vbl_end - 1))
-                       position = (position + 1) % vtotal;
+               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;
+                       }
+               }
        } else {
                /* Have access to pixelcount since start of frame.
                 * We can split this into vertical and horizontal
@@ -809,7 +829,8 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe,
        /* Helper routine in DRM core does all the work: */
        return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error,
                                                     vblank_time, flags,
-                                                    crtc);
+                                                    crtc,
+                                                    &to_intel_crtc(crtc)->config.adjusted_mode);
 }
 
 static bool intel_hpd_irq_event(struct drm_device *dev,
@@ -909,6 +930,11 @@ static void i915_hotplug_work_func(struct work_struct *work)
                drm_kms_helper_hotplug_event(dev);
 }
 
+static void intel_hpd_irq_uninstall(struct drm_i915_private *dev_priv)
+{
+       del_timer_sync(&dev_priv->hotplug_reenable_timer);
+}
+
 static void ironlake_rps_change_irq_handler(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -960,6 +986,43 @@ static void notify_ring(struct drm_device *dev,
        i915_queue_hangcheck(dev);
 }
 
+void gen6_set_pm_mask(struct drm_i915_private *dev_priv,
+                            u32 pm_iir, int new_delay)
+{
+       if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
+               if (new_delay >= dev_priv->rps.max_delay) {
+                       /* Mask UP THRESHOLD Interrupts */
+                       I915_WRITE(GEN6_PMINTRMSK,
+                                  I915_READ(GEN6_PMINTRMSK) |
+                                  GEN6_PM_RP_UP_THRESHOLD);
+                       dev_priv->rps.rp_up_masked = true;
+               }
+               if (dev_priv->rps.rp_down_masked) {
+                       /* UnMask DOWN THRESHOLD Interrupts */
+                       I915_WRITE(GEN6_PMINTRMSK,
+                                  I915_READ(GEN6_PMINTRMSK) &
+                                  ~GEN6_PM_RP_DOWN_THRESHOLD);
+                       dev_priv->rps.rp_down_masked = false;
+               }
+       } else if (pm_iir & GEN6_PM_RP_DOWN_THRESHOLD) {
+               if (new_delay <= dev_priv->rps.min_delay) {
+                       /* Mask DOWN THRESHOLD Interrupts */
+                       I915_WRITE(GEN6_PMINTRMSK,
+                                  I915_READ(GEN6_PMINTRMSK) |
+                                  GEN6_PM_RP_DOWN_THRESHOLD);
+                       dev_priv->rps.rp_down_masked = true;
+               }
+
+               if (dev_priv->rps.rp_up_masked) {
+                       /* UnMask UP THRESHOLD Interrupts */
+                       I915_WRITE(GEN6_PMINTRMSK,
+                                  I915_READ(GEN6_PMINTRMSK) &
+                                  ~GEN6_PM_RP_UP_THRESHOLD);
+                       dev_priv->rps.rp_up_masked = false;
+               }
+       }
+}
+
 static void gen6_pm_rps_work(struct work_struct *work)
 {
        drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
@@ -1017,6 +1080,8 @@ static void gen6_pm_rps_work(struct work_struct *work)
         */
        new_delay = clamp_t(int, new_delay,
                            dev_priv->rps.min_delay, dev_priv->rps.max_delay);
+
+       gen6_set_pm_mask(dev_priv, pm_iir, new_delay);
        dev_priv->rps.last_adj = new_delay - dev_priv->rps.cur_delay;
 
        if (IS_VALLEYVIEW(dev_priv->dev))
@@ -1230,12 +1295,16 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
        if (!hotplug_trigger)
                return;
 
+       DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
+                         hotplug_trigger);
+
        spin_lock(&dev_priv->irq_lock);
        for (i = 1; i < HPD_NUM_PINS; i++) {
 
-               WARN(((hpd[i] & hotplug_trigger) &&
-                     dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED),
-                    "Received HPD interrupt although disabled\n");
+               WARN_ONCE(hpd[i] & hotplug_trigger &&
+                         dev_priv->hpd_stats[i].hpd_mark == HPD_DISABLED,
+                         "Received HPD interrupt (0x%08x) on pin %d (0x%08x) although disabled\n",
+                         hotplug_trigger, i, hpd[i]);
 
                if (!(hpd[i] & hotplug_trigger) ||
                    dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED)
@@ -1418,8 +1487,6 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
        int pipe;
        u32 pipe_stats[I915_MAX_PIPES];
 
-       atomic_inc(&dev_priv->irq_received);
-
        while (true) {
                iir = I915_READ(VLV_IIR);
                gt_iir = I915_READ(GTIIR);
@@ -1440,12 +1507,8 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
                        /*
                         * Clear the PIPE*STAT regs before the IIR
                         */
-                       if (pipe_stats[pipe] & 0x8000ffff) {
-                               if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
-                                       DRM_DEBUG_DRIVER("pipe %c underrun\n",
-                                                        pipe_name(pipe));
+                       if (pipe_stats[pipe] & 0x8000ffff)
                                I915_WRITE(reg, pipe_stats[pipe]);
-                       }
                }
                spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
@@ -1460,6 +1523,10 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 
                        if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
                                i9xx_pipe_crc_irq_handler(dev, pipe);
+
+                       if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
+                           intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
+                               DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
                }
 
                /* Consume port.  Then clear IIR or we'll miss events */
@@ -1467,9 +1534,6 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
                        u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
                        u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
 
-                       DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
-                                        hotplug_status);
-
                        intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
 
                        if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X)
@@ -1539,12 +1603,12 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
        if (pch_iir & SDE_TRANSA_FIFO_UNDER)
                if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A,
                                                          false))
-                       DRM_DEBUG_DRIVER("PCH transcoder A FIFO underrun\n");
+                       DRM_ERROR("PCH transcoder A FIFO underrun\n");
 
        if (pch_iir & SDE_TRANSB_FIFO_UNDER)
                if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B,
                                                          false))
-                       DRM_DEBUG_DRIVER("PCH transcoder B FIFO underrun\n");
+                       DRM_ERROR("PCH transcoder B FIFO underrun\n");
 }
 
 static void ivb_err_int_handler(struct drm_device *dev)
@@ -1560,8 +1624,8 @@ static void ivb_err_int_handler(struct drm_device *dev)
                if (err_int & ERR_INT_FIFO_UNDERRUN(pipe)) {
                        if (intel_set_cpu_fifo_underrun_reporting(dev, pipe,
                                                                  false))
-                               DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n",
-                                                pipe_name(pipe));
+                               DRM_ERROR("Pipe %c FIFO underrun\n",
+                                         pipe_name(pipe));
                }
 
                if (err_int & ERR_INT_PIPE_CRC_DONE(pipe)) {
@@ -1586,17 +1650,17 @@ static void cpt_serr_int_handler(struct drm_device *dev)
        if (serr_int & SERR_INT_TRANS_A_FIFO_UNDERRUN)
                if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A,
                                                          false))
-                       DRM_DEBUG_DRIVER("PCH transcoder A FIFO underrun\n");
+                       DRM_ERROR("PCH transcoder A FIFO underrun\n");
 
        if (serr_int & SERR_INT_TRANS_B_FIFO_UNDERRUN)
                if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B,
                                                          false))
-                       DRM_DEBUG_DRIVER("PCH transcoder B FIFO underrun\n");
+                       DRM_ERROR("PCH transcoder B FIFO underrun\n");
 
        if (serr_int & SERR_INT_TRANS_C_FIFO_UNDERRUN)
                if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_C,
                                                          false))
-                       DRM_DEBUG_DRIVER("PCH transcoder C FIFO underrun\n");
+                       DRM_ERROR("PCH transcoder C FIFO underrun\n");
 
        I915_WRITE(SERR_INT, serr_int);
 }
@@ -1658,8 +1722,8 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
 
                if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe))
                        if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
-                               DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n",
-                                                pipe_name(pipe));
+                               DRM_ERROR("Pipe %c FIFO underrun\n",
+                                         pipe_name(pipe));
 
                if (de_iir & DE_PIPE_CRC_DONE(pipe))
                        i9xx_pipe_crc_irq_handler(dev, pipe);
@@ -1731,8 +1795,6 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
        u32 de_iir, gt_iir, de_ier, sde_ier = 0;
        irqreturn_t ret = IRQ_NONE;
 
-       atomic_inc(&dev_priv->irq_received);
-
        /* We get interrupts on unclaimed registers, so check for this before we
         * do any I915_{READ,WRITE}. */
        intel_uncore_check_errors(dev);
@@ -1801,8 +1863,6 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
        uint32_t tmp = 0;
        enum pipe pipe;
 
-       atomic_inc(&dev_priv->irq_received);
-
        master_ctl = I915_READ(GEN8_MASTER_IRQ);
        master_ctl &= ~GEN8_MASTER_IRQ_CONTROL;
        if (!master_ctl)
@@ -1864,8 +1924,8 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
                if (pipe_iir & GEN8_PIPE_FIFO_UNDERRUN) {
                        if (intel_set_cpu_fifo_underrun_reporting(dev, pipe,
                                                                  false))
-                               DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n",
-                                                pipe_name(pipe));
+                               DRM_ERROR("Pipe %c FIFO underrun\n",
+                                         pipe_name(pipe));
                }
 
                if (pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS) {
@@ -2472,9 +2532,8 @@ static void i915_hangcheck_elapsed(unsigned long data)
 #define BUSY 1
 #define KICK 5
 #define HUNG 20
-#define FIRE 30
 
-       if (!i915_enable_hangcheck)
+       if (!i915.enable_hangcheck)
                return;
 
        for_each_ring(ring, dev_priv, i) {
@@ -2556,7 +2615,7 @@ static void i915_hangcheck_elapsed(unsigned long data)
        }
 
        for_each_ring(ring, dev_priv, i) {
-               if (ring->hangcheck.score > FIRE) {
+               if (ring->hangcheck.score >= HANGCHECK_SCORE_RING_HUNG) {
                        DRM_INFO("%s on %s\n",
                                 stuck[i] ? "stuck" : "no progress",
                                 ring->name);
@@ -2576,7 +2635,7 @@ static void i915_hangcheck_elapsed(unsigned long data)
 void i915_queue_hangcheck(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       if (!i915_enable_hangcheck)
+       if (!i915.enable_hangcheck)
                return;
 
        mod_timer(&dev_priv->gpu_error.hangcheck_timer,
@@ -2625,8 +2684,6 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 
-       atomic_set(&dev_priv->irq_received, 0);
-
        I915_WRITE(HWSTAM, 0xeffe);
 
        I915_WRITE(DEIMR, 0xffffffff);
@@ -2643,8 +2700,6 @@ static void valleyview_irq_preinstall(struct drm_device *dev)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        int pipe;
 
-       atomic_set(&dev_priv->irq_received, 0);
-
        /* VLV magic */
        I915_WRITE(VLV_IMR, 0);
        I915_WRITE(RING_IMR(RENDER_RING_BASE), 0);
@@ -2674,8 +2729,6 @@ static void gen8_irq_preinstall(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe;
 
-       atomic_set(&dev_priv->irq_received, 0);
-
        I915_WRITE(GEN8_MASTER_IRQ, 0);
        POSTING_READ(GEN8_MASTER_IRQ);
 
@@ -2714,6 +2767,8 @@ static void gen8_irq_preinstall(struct drm_device *dev)
 #undef GEN8_IRQ_INIT_NDX
 
        POSTING_READ(GEN8_PCU_IIR);
+
+       ibx_irq_preinstall(dev);
 }
 
 static void ibx_hpd_irq_setup(struct drm_device *dev)
@@ -2998,8 +3053,6 @@ static void gen8_irq_uninstall(struct drm_device *dev)
        if (!dev_priv)
                return;
 
-       atomic_set(&dev_priv->irq_received, 0);
-
        I915_WRITE(GEN8_MASTER_IRQ, 0);
 
 #define GEN8_IRQ_FINI_NDX(type, which) do { \
@@ -3040,7 +3093,7 @@ static void valleyview_irq_uninstall(struct drm_device *dev)
        if (!dev_priv)
                return;
 
-       del_timer_sync(&dev_priv->hotplug_reenable_timer);
+       intel_hpd_irq_uninstall(dev_priv);
 
        for_each_pipe(pipe)
                I915_WRITE(PIPESTAT(pipe), 0xffff);
@@ -3063,7 +3116,7 @@ static void ironlake_irq_uninstall(struct drm_device *dev)
        if (!dev_priv)
                return;
 
-       del_timer_sync(&dev_priv->hotplug_reenable_timer);
+       intel_hpd_irq_uninstall(dev_priv);
 
        I915_WRITE(HWSTAM, 0xffffffff);
 
@@ -3092,8 +3145,6 @@ static void i8xx_irq_preinstall(struct drm_device * dev)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        int pipe;
 
-       atomic_set(&dev_priv->irq_received, 0);
-
        for_each_pipe(pipe)
                I915_WRITE(PIPESTAT(pipe), 0);
        I915_WRITE16(IMR, 0xffff);
@@ -3178,8 +3229,6 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
                I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
                I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
 
-       atomic_inc(&dev_priv->irq_received);
-
        iir = I915_READ16(IIR);
        if (iir == 0)
                return IRQ_NONE;
@@ -3201,12 +3250,8 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
                        /*
                         * Clear the PIPE*STAT regs before the IIR
                         */
-                       if (pipe_stats[pipe] & 0x8000ffff) {
-                               if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
-                                       DRM_DEBUG_DRIVER("pipe %c underrun\n",
-                                                        pipe_name(pipe));
+                       if (pipe_stats[pipe] & 0x8000ffff)
                                I915_WRITE(reg, pipe_stats[pipe]);
-                       }
                }
                spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
@@ -3220,7 +3265,7 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
 
                for_each_pipe(pipe) {
                        int plane = pipe;
-                       if (IS_MOBILE(dev))
+                       if (HAS_FBC(dev))
                                plane = !plane;
 
                        if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS &&
@@ -3229,6 +3274,10 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
 
                        if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
                                i9xx_pipe_crc_irq_handler(dev, pipe);
+
+                       if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
+                           intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
+                               DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
                }
 
                iir = new_iir;
@@ -3257,8 +3306,6 @@ static void i915_irq_preinstall(struct drm_device * dev)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        int pipe;
 
-       atomic_set(&dev_priv->irq_received, 0);
-
        if (I915_HAS_HOTPLUG(dev)) {
                I915_WRITE(PORT_HOTPLUG_EN, 0);
                I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
@@ -3364,8 +3411,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
                I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
        int pipe, ret = IRQ_NONE;
 
-       atomic_inc(&dev_priv->irq_received);
-
        iir = I915_READ(IIR);
        do {
                bool irq_received = (iir & ~flip_mask) != 0;
@@ -3386,9 +3431,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 
                        /* Clear the PIPE*STAT regs before the IIR */
                        if (pipe_stats[pipe] & 0x8000ffff) {
-                               if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
-                                       DRM_DEBUG_DRIVER("pipe %c underrun\n",
-                                                        pipe_name(pipe));
                                I915_WRITE(reg, pipe_stats[pipe]);
                                irq_received = true;
                        }
@@ -3404,9 +3446,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
                        u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
                        u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
 
-                       DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
-                                 hotplug_status);
-
                        intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
 
                        I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
@@ -3421,7 +3460,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 
                for_each_pipe(pipe) {
                        int plane = pipe;
-                       if (IS_MOBILE(dev))
+                       if (HAS_FBC(dev))
                                plane = !plane;
 
                        if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS &&
@@ -3433,6 +3472,10 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 
                        if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
                                i9xx_pipe_crc_irq_handler(dev, pipe);
+
+                       if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
+                           intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
+                               DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
                }
 
                if (blc_event || (iir & I915_ASLE_INTERRUPT))
@@ -3467,7 +3510,7 @@ static void i915_irq_uninstall(struct drm_device * dev)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        int pipe;
 
-       del_timer_sync(&dev_priv->hotplug_reenable_timer);
+       intel_hpd_irq_uninstall(dev_priv);
 
        if (I915_HAS_HOTPLUG(dev)) {
                I915_WRITE(PORT_HOTPLUG_EN, 0);
@@ -3491,8 +3534,6 @@ static void i965_irq_preinstall(struct drm_device * dev)
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        int pipe;
 
-       atomic_set(&dev_priv->irq_received, 0);
-
        I915_WRITE(PORT_HOTPLUG_EN, 0);
        I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
 
@@ -3601,21 +3642,17 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
        u32 iir, new_iir;
        u32 pipe_stats[I915_MAX_PIPES];
        unsigned long irqflags;
-       int irq_received;
        int ret = IRQ_NONE, pipe;
        u32 flip_mask =
                I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
                I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
 
-       atomic_inc(&dev_priv->irq_received);
-
        iir = I915_READ(IIR);
 
        for (;;) {
+               bool irq_received = (iir & ~flip_mask) != 0;
                bool blc_event = false;
 
-               irq_received = (iir & ~flip_mask) != 0;
-
                /* Can't rely on pipestat interrupt bit in iir as it might
                 * have been cleared after the pipestat interrupt was received.
                 * It doesn't set the bit in iir again, but it still produces
@@ -3633,11 +3670,8 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
                         * Clear the PIPE*STAT regs before the IIR
                         */
                        if (pipe_stats[pipe] & 0x8000ffff) {
-                               if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
-                                       DRM_DEBUG_DRIVER("pipe %c underrun\n",
-                                                        pipe_name(pipe));
                                I915_WRITE(reg, pipe_stats[pipe]);
-                               irq_received = 1;
+                               irq_received = true;
                        }
                }
                spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
@@ -3654,11 +3688,8 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
                                                                  HOTPLUG_INT_STATUS_G4X :
                                                                  HOTPLUG_INT_STATUS_I915);
 
-                       DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
-                                 hotplug_status);
-
                        intel_hpd_irq_handler(dev, hotplug_trigger,
-                                             IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915);
+                                             IS_G4X(dev) ? hpd_status_g4x : hpd_status_i915);
 
                        if (IS_G4X(dev) &&
                            (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X))
@@ -3686,8 +3717,11 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 
                        if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
                                i9xx_pipe_crc_irq_handler(dev, pipe);
-               }
 
+                       if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
+                           intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
+                               DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
+               }
 
                if (blc_event || (iir & I915_ASLE_INTERRUPT))
                        intel_opregion_asle_intr(dev);
@@ -3726,7 +3760,7 @@ static void i965_irq_uninstall(struct drm_device * dev)
        if (!dev_priv)
                return;
 
-       del_timer_sync(&dev_priv->hotplug_reenable_timer);
+       intel_hpd_irq_uninstall(dev_priv);
 
        I915_WRITE(PORT_HOTPLUG_EN, 0);
        I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
@@ -3743,7 +3777,7 @@ static void i965_irq_uninstall(struct drm_device * dev)
        I915_WRITE(IIR, I915_READ(IIR));
 }
 
-static void i915_reenable_hotplug_timer_func(unsigned long data)
+static void intel_hpd_irq_reenable(unsigned long data)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *)data;
        struct drm_device *dev = dev_priv->dev;
@@ -3790,7 +3824,7 @@ void intel_irq_init(struct drm_device *dev)
        setup_timer(&dev_priv->gpu_error.hangcheck_timer,
                    i915_hangcheck_elapsed,
                    (unsigned long) dev);
-       setup_timer(&dev_priv->hotplug_reenable_timer, i915_reenable_hotplug_timer_func,
+       setup_timer(&dev_priv->hotplug_reenable_timer, intel_hpd_irq_reenable,
                    (unsigned long) dev_priv);
 
        pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
@@ -3900,8 +3934,8 @@ void hsw_pc8_disable_interrupts(struct drm_device *dev)
        dev_priv->pc8.regsave.gtier = I915_READ(GTIER);
        dev_priv->pc8.regsave.gen6_pmimr = I915_READ(GEN6_PMIMR);
 
-       ironlake_disable_display_irq(dev_priv, ~DE_PCH_EVENT_IVB);
-       ibx_disable_display_interrupt(dev_priv, ~SDE_HOTPLUG_MASK_CPT);
+       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);
 
@@ -3915,34 +3949,26 @@ void hsw_pc8_restore_interrupts(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
-       uint32_t val, expected;
+       uint32_t val;
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 
        val = I915_READ(DEIMR);
-       expected = ~DE_PCH_EVENT_IVB;
-       WARN(val != expected, "DEIMR is 0x%08x, not 0x%08x\n", val, expected);
+       WARN(val != 0xffffffff, "DEIMR is 0x%08x\n", val);
 
-       val = I915_READ(SDEIMR) & ~SDE_HOTPLUG_MASK_CPT;
-       expected = ~SDE_HOTPLUG_MASK_CPT;
-       WARN(val != expected, "SDEIMR non-HPD bits are 0x%08x, not 0x%08x\n",
-            val, expected);
+       val = I915_READ(SDEIMR);
+       WARN(val != 0xffffffff, "SDEIMR is 0x%08x\n", val);
 
        val = I915_READ(GTIMR);
-       expected = 0xffffffff;
-       WARN(val != expected, "GTIMR is 0x%08x, not 0x%08x\n", val, expected);
+       WARN(val != 0xffffffff, "GTIMR is 0x%08x\n", val);
 
        val = I915_READ(GEN6_PMIMR);
-       expected = 0xffffffff;
-       WARN(val != expected, "GEN6_PMIMR is 0x%08x, not 0x%08x\n", val,
-            expected);
+       WARN(val != 0xffffffff, "GEN6_PMIMR is 0x%08x\n", val);
 
        dev_priv->pc8.irqs_disabled = false;
 
        ironlake_enable_display_irq(dev_priv, ~dev_priv->pc8.regsave.deimr);
-       ibx_enable_display_interrupt(dev_priv,
-                                    ~dev_priv->pc8.regsave.sdeimr &
-                                    ~SDE_HOTPLUG_MASK_CPT);
+       ibx_enable_display_interrupt(dev_priv, ~dev_priv->pc8.regsave.sdeimr);
        ilk_enable_gt_irq(dev_priv, ~dev_priv->pc8.regsave.gtimr);
        snb_enable_pm_irq(dev_priv, ~dev_priv->pc8.regsave.gen6_pmimr);
        I915_WRITE(GTIER, dev_priv->pc8.regsave.gtier);
This page took 0.04475 seconds and 5 git commands to generate.