]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
drm/i915: Extract intel_fifo_underrun.c
authorDaniel Vetter <daniel.vetter@ffwll.ch>
Tue, 30 Sep 2014 08:56:46 +0000 (10:56 +0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Fri, 24 Oct 2014 14:33:53 +0000 (16:33 +0200)
Prep work for some nice documentation. Requires that we export the
display irq enable/disable functions on ilk/ibx. But we already export
them for vlv/i915. So not more inconsistency.

v2: Rebase on top of skl stage 1.

Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_fifo_underrun.c [new file with mode: 0644]

index 3a6bce047f6fec87b441fda1e024d17357ffcf0d..75fd7de9bf4bb0332b1c1d86b64acfddd4dbef2a 100644 (file)
@@ -45,6 +45,7 @@ i915-y += intel_renderstate_gen6.o \
 # modesetting core code
 i915-y += intel_bios.o \
          intel_display.o \
+         intel_fifo_underrun.o \
          intel_frontbuffer.o \
          intel_modes.o \
          intel_overlay.o \
index 9962da2024563027d28cbdd7f3c499ee2333ed8e..26724c54bd8030ce7b5df3c3f291e3de50f9ece4 100644 (file)
@@ -2312,6 +2312,17 @@ i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
 
 void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv);
 void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv);
+void
+ironlake_enable_display_irq(struct drm_i915_private *dev_priv, u32 mask);
+void
+ironlake_disable_display_irq(struct drm_i915_private *dev_priv, u32 mask);
+void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
+                                 uint32_t interrupt_mask,
+                                 uint32_t enabled_irq_mask);
+#define ibx_enable_display_interrupt(dev_priv, bits) \
+       ibx_display_interrupt_update((dev_priv), (bits), (bits))
+#define ibx_disable_display_interrupt(dev_priv, bits) \
+       ibx_display_interrupt_update((dev_priv), (bits), 0)
 
 /* i915_gem.c */
 int i915_gem_init_ioctl(struct drm_device *dev, void *data,
index f17bbf3ac136994464bc5881729d4db27a485c2c..536efa277b0131a857d0a30e1481478709c34f4f 100644 (file)
@@ -139,7 +139,7 @@ static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */
 } while (0)
 
 /* For display hotplug interrupt */
-static void
+void
 ironlake_enable_display_irq(struct drm_i915_private *dev_priv, u32 mask)
 {
        assert_spin_locked(&dev_priv->irq_lock);
@@ -154,7 +154,7 @@ ironlake_enable_display_irq(struct drm_i915_private *dev_priv, u32 mask)
        }
 }
 
-static void
+void
 ironlake_disable_display_irq(struct drm_i915_private *dev_priv, u32 mask)
 {
        assert_spin_locked(&dev_priv->irq_lock);
@@ -238,24 +238,6 @@ void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
        snb_update_pm_irq(dev_priv, mask, 0);
 }
 
-static bool ivb_can_enable_err_int(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *crtc;
-       enum pipe pipe;
-
-       assert_spin_locked(&dev_priv->irq_lock);
-
-       for_each_pipe(dev_priv, pipe) {
-               crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
-
-               if (crtc->cpu_fifo_underrun_disabled)
-                       return false;
-       }
-
-       return true;
-}
-
 /**
   * bdw_update_pm_irq - update GT interrupt 2
   * @dev_priv: driver private
@@ -296,130 +278,15 @@ void gen8_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask)
        bdw_update_pm_irq(dev_priv, mask, 0);
 }
 
-static bool cpt_can_enable_serr_int(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       enum pipe pipe;
-       struct intel_crtc *crtc;
-
-       assert_spin_locked(&dev_priv->irq_lock);
-
-       for_each_pipe(dev_priv, pipe) {
-               crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
-
-               if (crtc->pch_fifo_underrun_disabled)
-                       return false;
-       }
-
-       return true;
-}
-
-void i9xx_check_fifo_underruns(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *crtc;
-
-       spin_lock_irq(&dev_priv->irq_lock);
-
-       for_each_intel_crtc(dev, crtc) {
-               u32 reg = PIPESTAT(crtc->pipe);
-               u32 pipestat;
-
-               if (crtc->cpu_fifo_underrun_disabled)
-                       continue;
-
-               pipestat = I915_READ(reg) & 0xffff0000;
-               if ((pipestat & PIPE_FIFO_UNDERRUN_STATUS) == 0)
-                       continue;
-
-               I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
-               POSTING_READ(reg);
-
-               DRM_ERROR("pipe %c underrun\n", pipe_name(crtc->pipe));
-       }
-
-       spin_unlock_irq(&dev_priv->irq_lock);
-}
-
-static void i9xx_set_fifo_underrun_reporting(struct drm_device *dev,
-                                            enum pipe pipe,
-                                            bool enable, bool old)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 reg = PIPESTAT(pipe);
-       u32 pipestat = I915_READ(reg) & 0xffff0000;
-
-       assert_spin_locked(&dev_priv->irq_lock);
-
-       if (enable) {
-               I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
-               POSTING_READ(reg);
-       } else {
-               if (old && pipestat & PIPE_FIFO_UNDERRUN_STATUS)
-                       DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
-       }
-}
-
-static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev,
-                                                enum pipe pipe, bool enable)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t bit = (pipe == PIPE_A) ? DE_PIPEA_FIFO_UNDERRUN :
-                                         DE_PIPEB_FIFO_UNDERRUN;
-
-       if (enable)
-               ironlake_enable_display_irq(dev_priv, bit);
-       else
-               ironlake_disable_display_irq(dev_priv, bit);
-}
-
-static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev,
-                                                 enum pipe pipe,
-                                                 bool enable, bool old)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       if (enable) {
-               I915_WRITE(GEN7_ERR_INT, ERR_INT_FIFO_UNDERRUN(pipe));
-
-               if (!ivb_can_enable_err_int(dev))
-                       return;
-
-               ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
-       } else {
-               ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
-
-               if (old &&
-                   I915_READ(GEN7_ERR_INT) & ERR_INT_FIFO_UNDERRUN(pipe)) {
-                       DRM_ERROR("uncleared fifo underrun on pipe %c\n",
-                                 pipe_name(pipe));
-               }
-       }
-}
-
-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
  * @interrupt_mask: mask of interrupt bits to update
  * @enabled_irq_mask: mask of interrupt bits to enable
  */
-static void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
-                                        uint32_t interrupt_mask,
-                                        uint32_t enabled_irq_mask)
+void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
+                                 uint32_t interrupt_mask,
+                                 uint32_t enabled_irq_mask)
 {
        uint32_t sdeimr = I915_READ(SDEIMR);
        sdeimr &= ~interrupt_mask;
@@ -433,160 +300,6 @@ static void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
        I915_WRITE(SDEIMR, sdeimr);
        POSTING_READ(SDEIMR);
 }
-#define ibx_enable_display_interrupt(dev_priv, bits) \
-       ibx_display_interrupt_update((dev_priv), (bits), (bits))
-#define ibx_disable_display_interrupt(dev_priv, bits) \
-       ibx_display_interrupt_update((dev_priv), (bits), 0)
-
-static void ibx_set_fifo_underrun_reporting(struct drm_device *dev,
-                                           enum transcoder pch_transcoder,
-                                           bool enable)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t bit = (pch_transcoder == TRANSCODER_A) ?
-                      SDE_TRANSA_FIFO_UNDER : SDE_TRANSB_FIFO_UNDER;
-
-       if (enable)
-               ibx_enable_display_interrupt(dev_priv, bit);
-       else
-               ibx_disable_display_interrupt(dev_priv, bit);
-}
-
-static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
-                                           enum transcoder pch_transcoder,
-                                           bool enable, bool old)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (enable) {
-               I915_WRITE(SERR_INT,
-                          SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder));
-
-               if (!cpt_can_enable_serr_int(dev))
-                       return;
-
-               ibx_enable_display_interrupt(dev_priv, SDE_ERROR_CPT);
-       } else {
-               ibx_disable_display_interrupt(dev_priv, SDE_ERROR_CPT);
-
-               if (old && I915_READ(SERR_INT) &
-                   SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder)) {
-                       DRM_ERROR("uncleared pch fifo underrun on pch transcoder %c\n",
-                                 transcoder_name(pch_transcoder));
-               }
-       }
-}
-
-/**
- * intel_set_cpu_fifo_underrun_reporting - enable/disable FIFO underrun messages
- * @dev: drm device
- * @pipe: pipe
- * @enable: true if we want to report FIFO underrun errors, false otherwise
- *
- * This function makes us disable or enable CPU fifo underruns for a specific
- * pipe. Notice that on some Gens (e.g. IVB, HSW), disabling FIFO underrun
- * reporting for one pipe may also disable all the other CPU error interruts for
- * the other pipes, due to the fact that there's just one interrupt mask/enable
- * bit for all the pipes.
- *
- * Returns the previous state of underrun reporting.
- */
-static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
-                                                   enum pipe pipe, bool enable)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       bool old;
-
-       assert_spin_locked(&dev_priv->irq_lock);
-
-       old = !intel_crtc->cpu_fifo_underrun_disabled;
-       intel_crtc->cpu_fifo_underrun_disabled = !enable;
-
-       if (HAS_GMCH_DISPLAY(dev))
-               i9xx_set_fifo_underrun_reporting(dev, pipe, enable, old);
-       else if (IS_GEN5(dev) || IS_GEN6(dev))
-               ironlake_set_fifo_underrun_reporting(dev, pipe, enable);
-       else if (IS_GEN7(dev))
-               ivybridge_set_fifo_underrun_reporting(dev, pipe, enable, old);
-       else if (IS_GEN8(dev) || IS_GEN9(dev))
-               broadwell_set_fifo_underrun_reporting(dev, pipe, enable);
-
-       return old;
-}
-
-bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
-                                          enum pipe pipe, bool enable)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       unsigned long flags;
-       bool ret;
-
-       spin_lock_irqsave(&dev_priv->irq_lock, flags);
-       ret = __intel_set_cpu_fifo_underrun_reporting(dev, pipe, enable);
-       spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
-
-       return ret;
-}
-
-static bool __cpu_fifo_underrun_reporting_enabled(struct drm_device *dev,
-                                                 enum pipe pipe)
-{
-       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);
-
-       return !intel_crtc->cpu_fifo_underrun_disabled;
-}
-
-/**
- * intel_set_pch_fifo_underrun_reporting - enable/disable FIFO underrun messages
- * @dev: drm device
- * @pch_transcoder: the PCH transcoder (same as pipe on IVB and older)
- * @enable: true if we want to report FIFO underrun errors, false otherwise
- *
- * This function makes us disable or enable PCH fifo underruns for a specific
- * PCH transcoder. Notice that on some PCHs (e.g. CPT/PPT), disabling FIFO
- * underrun reporting for one transcoder may also disable all the other PCH
- * error interruts for the other transcoders, due to the fact that there's just
- * one interrupt mask/enable bit for all the transcoders.
- *
- * Returns the previous state of underrun reporting.
- */
-bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
-                                          enum transcoder pch_transcoder,
-                                          bool enable)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder];
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       unsigned long flags;
-       bool old;
-
-       /*
-        * NOTE: Pre-LPT has a fixed cpu pipe -> pch transcoder mapping, but LPT
-        * has only one pch transcoder A that all pipes can use. To avoid racy
-        * pch transcoder -> pipe lookups from interrupt code simply store the
-        * underrun statistics in crtc A. Since we never expose this anywhere
-        * nor use it outside of the fifo underrun code here using the "wrong"
-        * crtc on LPT won't cause issues.
-        */
-
-       spin_lock_irqsave(&dev_priv->irq_lock, flags);
-
-       old = !intel_crtc->pch_fifo_underrun_disabled;
-       intel_crtc->pch_fifo_underrun_disabled = !enable;
-
-       if (HAS_PCH_IBX(dev))
-               ibx_set_fifo_underrun_reporting(dev, pch_transcoder, enable);
-       else
-               cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable, old);
-
-       spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
-       return old;
-}
-
 
 static void
 __i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
index 94993d23e5475d8fbba11d0437f35d4a7e000eec..321701da12ec1784bcf7473ac8d2caef857655e4 100644 (file)
@@ -755,12 +755,17 @@ static inline unsigned int intel_num_planes(struct intel_crtc *crtc)
        return INTEL_INFO(crtc->base.dev)->num_sprites[crtc->pipe] + 1;
 }
 
-/* i915_irq.c */
+/* intel_fifo_underrun.c */
 bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
                                           enum pipe pipe, bool enable);
 bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
                                           enum transcoder pch_transcoder,
                                           bool enable);
+void i9xx_check_fifo_underruns(struct drm_device *dev);
+bool __cpu_fifo_underrun_reporting_enabled(struct drm_device *dev,
+                                          enum pipe pipe);
+
+/* i915_irq.c */
 void gen5_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
 void gen5_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
 void gen6_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
@@ -779,7 +784,6 @@ static inline bool intel_irqs_enabled(struct drm_i915_private *dev_priv)
 }
 
 int intel_get_crtc_scanline(struct intel_crtc *crtc);
-void i9xx_check_fifo_underruns(struct drm_device *dev);
 void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv);
 
 /* intel_crt.c */
diff --git a/drivers/gpu/drm/i915/intel_fifo_underrun.c b/drivers/gpu/drm/i915/intel_fifo_underrun.c
new file mode 100644 (file)
index 0000000..8e79d2b
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+#include "i915_drv.h"
+#include "intel_drv.h"
+
+static bool ivb_can_enable_err_int(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *crtc;
+       enum pipe pipe;
+
+       assert_spin_locked(&dev_priv->irq_lock);
+
+       for_each_pipe(dev_priv, pipe) {
+               crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+
+               if (crtc->cpu_fifo_underrun_disabled)
+                       return false;
+       }
+
+       return true;
+}
+
+static bool cpt_can_enable_serr_int(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum pipe pipe;
+       struct intel_crtc *crtc;
+
+       assert_spin_locked(&dev_priv->irq_lock);
+
+       for_each_pipe(dev_priv, pipe) {
+               crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+
+               if (crtc->pch_fifo_underrun_disabled)
+                       return false;
+       }
+
+       return true;
+}
+
+void i9xx_check_fifo_underruns(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *crtc;
+
+       spin_lock_irq(&dev_priv->irq_lock);
+
+       for_each_intel_crtc(dev, crtc) {
+               u32 reg = PIPESTAT(crtc->pipe);
+               u32 pipestat;
+
+               if (crtc->cpu_fifo_underrun_disabled)
+                       continue;
+
+               pipestat = I915_READ(reg) & 0xffff0000;
+               if ((pipestat & PIPE_FIFO_UNDERRUN_STATUS) == 0)
+                       continue;
+
+               I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
+               POSTING_READ(reg);
+
+               DRM_ERROR("pipe %c underrun\n", pipe_name(crtc->pipe));
+       }
+
+       spin_unlock_irq(&dev_priv->irq_lock);
+}
+
+static void i9xx_set_fifo_underrun_reporting(struct drm_device *dev,
+                                            enum pipe pipe,
+                                            bool enable, bool old)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 reg = PIPESTAT(pipe);
+       u32 pipestat = I915_READ(reg) & 0xffff0000;
+
+       assert_spin_locked(&dev_priv->irq_lock);
+
+       if (enable) {
+               I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
+               POSTING_READ(reg);
+       } else {
+               if (old && pipestat & PIPE_FIFO_UNDERRUN_STATUS)
+                       DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
+       }
+}
+
+static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev,
+                                                enum pipe pipe, bool enable)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t bit = (pipe == PIPE_A) ? DE_PIPEA_FIFO_UNDERRUN :
+                                         DE_PIPEB_FIFO_UNDERRUN;
+
+       if (enable)
+               ironlake_enable_display_irq(dev_priv, bit);
+       else
+               ironlake_disable_display_irq(dev_priv, bit);
+}
+
+static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev,
+                                                 enum pipe pipe,
+                                                 bool enable, bool old)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       if (enable) {
+               I915_WRITE(GEN7_ERR_INT, ERR_INT_FIFO_UNDERRUN(pipe));
+
+               if (!ivb_can_enable_err_int(dev))
+                       return;
+
+               ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
+       } else {
+               ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
+
+               if (old &&
+                   I915_READ(GEN7_ERR_INT) & ERR_INT_FIFO_UNDERRUN(pipe)) {
+                       DRM_ERROR("uncleared fifo underrun on pipe %c\n",
+                                 pipe_name(pipe));
+               }
+       }
+}
+
+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));
+}
+
+static void ibx_set_fifo_underrun_reporting(struct drm_device *dev,
+                                           enum transcoder pch_transcoder,
+                                           bool enable)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t bit = (pch_transcoder == TRANSCODER_A) ?
+                      SDE_TRANSA_FIFO_UNDER : SDE_TRANSB_FIFO_UNDER;
+
+       if (enable)
+               ibx_enable_display_interrupt(dev_priv, bit);
+       else
+               ibx_disable_display_interrupt(dev_priv, bit);
+}
+
+static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
+                                           enum transcoder pch_transcoder,
+                                           bool enable, bool old)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (enable) {
+               I915_WRITE(SERR_INT,
+                          SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder));
+
+               if (!cpt_can_enable_serr_int(dev))
+                       return;
+
+               ibx_enable_display_interrupt(dev_priv, SDE_ERROR_CPT);
+       } else {
+               ibx_disable_display_interrupt(dev_priv, SDE_ERROR_CPT);
+
+               if (old && I915_READ(SERR_INT) &
+                   SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder)) {
+                       DRM_ERROR("uncleared pch fifo underrun on pch transcoder %c\n",
+                                 transcoder_name(pch_transcoder));
+               }
+       }
+}
+
+/**
+ * intel_set_cpu_fifo_underrun_reporting - enable/disable FIFO underrun messages
+ * @dev: drm device
+ * @pipe: pipe
+ * @enable: true if we want to report FIFO underrun errors, false otherwise
+ *
+ * This function makes us disable or enable CPU fifo underruns for a specific
+ * pipe. Notice that on some Gens (e.g. IVB, HSW), disabling FIFO underrun
+ * reporting for one pipe may also disable all the other CPU error interruts for
+ * the other pipes, due to the fact that there's just one interrupt mask/enable
+ * bit for all the pipes.
+ *
+ * Returns the previous state of underrun reporting.
+ */
+static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
+                                                   enum pipe pipe, bool enable)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       bool old;
+
+       assert_spin_locked(&dev_priv->irq_lock);
+
+       old = !intel_crtc->cpu_fifo_underrun_disabled;
+       intel_crtc->cpu_fifo_underrun_disabled = !enable;
+
+       if (HAS_GMCH_DISPLAY(dev))
+               i9xx_set_fifo_underrun_reporting(dev, pipe, enable, old);
+       else if (IS_GEN5(dev) || IS_GEN6(dev))
+               ironlake_set_fifo_underrun_reporting(dev, pipe, enable);
+       else if (IS_GEN7(dev))
+               ivybridge_set_fifo_underrun_reporting(dev, pipe, enable, old);
+       else if (IS_GEN8(dev) || IS_GEN9(dev))
+               broadwell_set_fifo_underrun_reporting(dev, pipe, enable);
+
+       return old;
+}
+
+bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
+                                          enum pipe pipe, bool enable)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long flags;
+       bool ret;
+
+       spin_lock_irqsave(&dev_priv->irq_lock, flags);
+       ret = __intel_set_cpu_fifo_underrun_reporting(dev, pipe, enable);
+       spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+
+       return ret;
+}
+
+bool __cpu_fifo_underrun_reporting_enabled(struct drm_device *dev,
+                                          enum pipe pipe)
+{
+       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);
+
+       return !intel_crtc->cpu_fifo_underrun_disabled;
+}
+
+/**
+ * intel_set_pch_fifo_underrun_reporting - enable/disable FIFO underrun messages
+ * @dev: drm device
+ * @pch_transcoder: the PCH transcoder (same as pipe on IVB and older)
+ * @enable: true if we want to report FIFO underrun errors, false otherwise
+ *
+ * This function makes us disable or enable PCH fifo underruns for a specific
+ * PCH transcoder. Notice that on some PCHs (e.g. CPT/PPT), disabling FIFO
+ * underrun reporting for one transcoder may also disable all the other PCH
+ * error interruts for the other transcoders, due to the fact that there's just
+ * one interrupt mask/enable bit for all the transcoders.
+ *
+ * Returns the previous state of underrun reporting.
+ */
+bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
+                                          enum transcoder pch_transcoder,
+                                          bool enable)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder];
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       unsigned long flags;
+       bool old;
+
+       /*
+        * NOTE: Pre-LPT has a fixed cpu pipe -> pch transcoder mapping, but LPT
+        * has only one pch transcoder A that all pipes can use. To avoid racy
+        * pch transcoder -> pipe lookups from interrupt code simply store the
+        * underrun statistics in crtc A. Since we never expose this anywhere
+        * nor use it outside of the fifo underrun code here using the "wrong"
+        * crtc on LPT won't cause issues.
+        */
+
+       spin_lock_irqsave(&dev_priv->irq_lock, flags);
+
+       old = !intel_crtc->pch_fifo_underrun_disabled;
+       intel_crtc->pch_fifo_underrun_disabled = !enable;
+
+       if (HAS_PCH_IBX(dev))
+               ibx_set_fifo_underrun_reporting(dev, pch_transcoder, enable);
+       else
+               cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable, old);
+
+       spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+       return old;
+}