LCOV - code coverage report
Current view: top level - dev/pci/drm/i915 - intel_fifo_underrun.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 142 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 14 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright © 2014 Intel Corporation
       3             :  *
       4             :  * Permission is hereby granted, free of charge, to any person obtaining a
       5             :  * copy of this software and associated documentation files (the "Software"),
       6             :  * to deal in the Software without restriction, including without limitation
       7             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
       8             :  * and/or sell copies of the Software, and to permit persons to whom the
       9             :  * Software is furnished to do so, subject to the following conditions:
      10             :  *
      11             :  * The above copyright notice and this permission notice (including the next
      12             :  * paragraph) shall be included in all copies or substantial portions of the
      13             :  * Software.
      14             :  *
      15             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      18             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      20             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
      21             :  * IN THE SOFTWARE.
      22             :  *
      23             :  * Authors:
      24             :  *    Daniel Vetter <daniel.vetter@ffwll.ch>
      25             :  *
      26             :  */
      27             : 
      28             : #include "i915_drv.h"
      29             : #include "intel_drv.h"
      30             : 
      31             : /**
      32             :  * DOC: fifo underrun handling
      33             :  *
      34             :  * The i915 driver checks for display fifo underruns using the interrupt signals
      35             :  * provided by the hardware. This is enabled by default and fairly useful to
      36             :  * debug display issues, especially watermark settings.
      37             :  *
      38             :  * If an underrun is detected this is logged into dmesg. To avoid flooding logs
      39             :  * and occupying the cpu underrun interrupts are disabled after the first
      40             :  * occurrence until the next modeset on a given pipe.
      41             :  *
      42             :  * Note that underrun detection on gmch platforms is a bit more ugly since there
      43             :  * is no interrupt (despite that the signalling bit is in the PIPESTAT pipe
      44             :  * interrupt register). Also on some other platforms underrun interrupts are
      45             :  * shared, which means that if we detect an underrun we need to disable underrun
      46             :  * reporting on all pipes.
      47             :  *
      48             :  * The code also supports underrun detection on the PCH transcoder.
      49             :  */
      50             : 
      51           0 : static bool ivb_can_enable_err_int(struct drm_device *dev)
      52             : {
      53           0 :         struct drm_i915_private *dev_priv = dev->dev_private;
      54             :         struct intel_crtc *crtc;
      55             :         enum pipe pipe;
      56             : 
      57           0 :         assert_spin_locked(&dev_priv->irq_lock);
      58             : 
      59           0 :         for_each_pipe(dev_priv, pipe) {
      60           0 :                 crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
      61             : 
      62           0 :                 if (crtc->cpu_fifo_underrun_disabled)
      63           0 :                         return false;
      64             :         }
      65             : 
      66           0 :         return true;
      67           0 : }
      68             : 
      69           0 : static bool cpt_can_enable_serr_int(struct drm_device *dev)
      70             : {
      71           0 :         struct drm_i915_private *dev_priv = dev->dev_private;
      72             :         enum pipe pipe;
      73             :         struct intel_crtc *crtc;
      74             : 
      75           0 :         assert_spin_locked(&dev_priv->irq_lock);
      76             : 
      77           0 :         for_each_pipe(dev_priv, pipe) {
      78           0 :                 crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
      79             : 
      80           0 :                 if (crtc->pch_fifo_underrun_disabled)
      81           0 :                         return false;
      82             :         }
      83             : 
      84           0 :         return true;
      85           0 : }
      86             : 
      87             : /**
      88             :  * i9xx_check_fifo_underruns - check for fifo underruns
      89             :  * @dev_priv: i915 device instance
      90             :  *
      91             :  * This function checks for fifo underruns on GMCH platforms. This needs to be
      92             :  * done manually on modeset to make sure that we catch all underruns since they
      93             :  * do not generate an interrupt by themselves on these platforms.
      94             :  */
      95           0 : void i9xx_check_fifo_underruns(struct drm_i915_private *dev_priv)
      96             : {
      97             :         struct intel_crtc *crtc;
      98             : 
      99           0 :         spin_lock_irq(&dev_priv->irq_lock);
     100             : 
     101           0 :         for_each_intel_crtc(dev_priv->dev, crtc) {
     102           0 :                 u32 reg = PIPESTAT(crtc->pipe);
     103             :                 u32 pipestat;
     104             : 
     105           0 :                 if (crtc->cpu_fifo_underrun_disabled)
     106           0 :                         continue;
     107             : 
     108           0 :                 pipestat = I915_READ(reg) & 0xffff0000;
     109           0 :                 if ((pipestat & PIPE_FIFO_UNDERRUN_STATUS) == 0)
     110           0 :                         continue;
     111             : 
     112           0 :                 I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
     113           0 :                 POSTING_READ(reg);
     114             : 
     115           0 :                 DRM_ERROR("pipe %c underrun\n", pipe_name(crtc->pipe));
     116           0 :         }
     117             : 
     118           0 :         spin_unlock_irq(&dev_priv->irq_lock);
     119           0 : }
     120             : 
     121           0 : static void i9xx_set_fifo_underrun_reporting(struct drm_device *dev,
     122             :                                              enum pipe pipe,
     123             :                                              bool enable, bool old)
     124             : {
     125           0 :         struct drm_i915_private *dev_priv = dev->dev_private;
     126           0 :         u32 reg = PIPESTAT(pipe);
     127           0 :         u32 pipestat = I915_READ(reg) & 0xffff0000;
     128             : 
     129           0 :         assert_spin_locked(&dev_priv->irq_lock);
     130             : 
     131           0 :         if (enable) {
     132           0 :                 I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
     133           0 :                 POSTING_READ(reg);
     134           0 :         } else {
     135           0 :                 if (old && pipestat & PIPE_FIFO_UNDERRUN_STATUS)
     136           0 :                         DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
     137             :         }
     138           0 : }
     139             : 
     140           0 : static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev,
     141             :                                                  enum pipe pipe, bool enable)
     142             : {
     143           0 :         struct drm_i915_private *dev_priv = dev->dev_private;
     144           0 :         uint32_t bit = (pipe == PIPE_A) ? DE_PIPEA_FIFO_UNDERRUN :
     145             :                                           DE_PIPEB_FIFO_UNDERRUN;
     146             : 
     147           0 :         if (enable)
     148           0 :                 ironlake_enable_display_irq(dev_priv, bit);
     149             :         else
     150           0 :                 ironlake_disable_display_irq(dev_priv, bit);
     151           0 : }
     152             : 
     153           0 : static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev,
     154             :                                                   enum pipe pipe,
     155             :                                                   bool enable, bool old)
     156             : {
     157           0 :         struct drm_i915_private *dev_priv = dev->dev_private;
     158           0 :         if (enable) {
     159           0 :                 I915_WRITE(GEN7_ERR_INT, ERR_INT_FIFO_UNDERRUN(pipe));
     160             : 
     161           0 :                 if (!ivb_can_enable_err_int(dev))
     162           0 :                         return;
     163             : 
     164           0 :                 ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
     165           0 :         } else {
     166           0 :                 ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
     167             : 
     168           0 :                 if (old &&
     169           0 :                     I915_READ(GEN7_ERR_INT) & ERR_INT_FIFO_UNDERRUN(pipe)) {
     170           0 :                         DRM_ERROR("uncleared fifo underrun on pipe %c\n",
     171             :                                   pipe_name(pipe));
     172           0 :                 }
     173             :         }
     174           0 : }
     175             : 
     176           0 : static void broadwell_set_fifo_underrun_reporting(struct drm_device *dev,
     177             :                                                   enum pipe pipe, bool enable)
     178             : {
     179           0 :         struct drm_i915_private *dev_priv = dev->dev_private;
     180             : 
     181           0 :         assert_spin_locked(&dev_priv->irq_lock);
     182             : 
     183           0 :         if (enable)
     184           0 :                 dev_priv->de_irq_mask[pipe] &= ~GEN8_PIPE_FIFO_UNDERRUN;
     185             :         else
     186           0 :                 dev_priv->de_irq_mask[pipe] |= GEN8_PIPE_FIFO_UNDERRUN;
     187           0 :         I915_WRITE(GEN8_DE_PIPE_IMR(pipe), dev_priv->de_irq_mask[pipe]);
     188           0 :         POSTING_READ(GEN8_DE_PIPE_IMR(pipe));
     189           0 : }
     190             : 
     191           0 : static void ibx_set_fifo_underrun_reporting(struct drm_device *dev,
     192             :                                             enum transcoder pch_transcoder,
     193             :                                             bool enable)
     194             : {
     195           0 :         struct drm_i915_private *dev_priv = dev->dev_private;
     196           0 :         uint32_t bit = (pch_transcoder == TRANSCODER_A) ?
     197             :                        SDE_TRANSA_FIFO_UNDER : SDE_TRANSB_FIFO_UNDER;
     198             : 
     199           0 :         if (enable)
     200           0 :                 ibx_enable_display_interrupt(dev_priv, bit);
     201             :         else
     202           0 :                 ibx_disable_display_interrupt(dev_priv, bit);
     203           0 : }
     204             : 
     205           0 : static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
     206             :                                             enum transcoder pch_transcoder,
     207             :                                             bool enable, bool old)
     208             : {
     209           0 :         struct drm_i915_private *dev_priv = dev->dev_private;
     210             : 
     211           0 :         if (enable) {
     212           0 :                 I915_WRITE(SERR_INT,
     213             :                            SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder));
     214             : 
     215           0 :                 if (!cpt_can_enable_serr_int(dev))
     216           0 :                         return;
     217             : 
     218           0 :                 ibx_enable_display_interrupt(dev_priv, SDE_ERROR_CPT);
     219           0 :         } else {
     220           0 :                 ibx_disable_display_interrupt(dev_priv, SDE_ERROR_CPT);
     221             : 
     222           0 :                 if (old && I915_READ(SERR_INT) &
     223           0 :                     SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder)) {
     224           0 :                         DRM_ERROR("uncleared pch fifo underrun on pch transcoder %c\n",
     225             :                                   transcoder_name(pch_transcoder));
     226           0 :                 }
     227             :         }
     228           0 : }
     229             : 
     230           0 : static bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
     231             :                                                     enum pipe pipe, bool enable)
     232             : {
     233           0 :         struct drm_i915_private *dev_priv = dev->dev_private;
     234           0 :         struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
     235           0 :         struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
     236             :         bool old;
     237             : 
     238           0 :         assert_spin_locked(&dev_priv->irq_lock);
     239             : 
     240           0 :         old = !intel_crtc->cpu_fifo_underrun_disabled;
     241           0 :         intel_crtc->cpu_fifo_underrun_disabled = !enable;
     242             : 
     243           0 :         if (HAS_GMCH_DISPLAY(dev))
     244           0 :                 i9xx_set_fifo_underrun_reporting(dev, pipe, enable, old);
     245           0 :         else if (IS_GEN5(dev) || IS_GEN6(dev))
     246           0 :                 ironlake_set_fifo_underrun_reporting(dev, pipe, enable);
     247           0 :         else if (IS_GEN7(dev))
     248           0 :                 ivybridge_set_fifo_underrun_reporting(dev, pipe, enable, old);
     249           0 :         else if (IS_GEN8(dev) || IS_GEN9(dev))
     250           0 :                 broadwell_set_fifo_underrun_reporting(dev, pipe, enable);
     251             : 
     252           0 :         return old;
     253             : }
     254             : 
     255             : /**
     256             :  * intel_set_cpu_fifo_underrun_reporting - set cpu fifo underrrun reporting state
     257             :  * @dev_priv: i915 device instance
     258             :  * @pipe: (CPU) pipe to set state for
     259             :  * @enable: whether underruns should be reported or not
     260             :  *
     261             :  * This function sets the fifo underrun state for @pipe. It is used in the
     262             :  * modeset code to avoid false positives since on many platforms underruns are
     263             :  * expected when disabling or enabling the pipe.
     264             :  *
     265             :  * Notice that on some platforms disabling underrun reports for one pipe
     266             :  * disables for all due to shared interrupts. Actual reporting is still per-pipe
     267             :  * though.
     268             :  *
     269             :  * Returns the previous state of underrun reporting.
     270             :  */
     271           0 : bool intel_set_cpu_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
     272             :                                            enum pipe pipe, bool enable)
     273             : {
     274             :         unsigned long flags;
     275             :         bool ret;
     276             : 
     277           0 :         spin_lock_irqsave(&dev_priv->irq_lock, flags);
     278           0 :         ret = __intel_set_cpu_fifo_underrun_reporting(dev_priv->dev, pipe,
     279             :                                                       enable);
     280           0 :         spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
     281             : 
     282           0 :         return ret;
     283             : }
     284             : 
     285             : /**
     286             :  * intel_set_pch_fifo_underrun_reporting - set PCH fifo underrun reporting state
     287             :  * @dev_priv: i915 device instance
     288             :  * @pch_transcoder: the PCH transcoder (same as pipe on IVB and older)
     289             :  * @enable: whether underruns should be reported or not
     290             :  *
     291             :  * This function makes us disable or enable PCH fifo underruns for a specific
     292             :  * PCH transcoder. Notice that on some PCHs (e.g. CPT/PPT), disabling FIFO
     293             :  * underrun reporting for one transcoder may also disable all the other PCH
     294             :  * error interruts for the other transcoders, due to the fact that there's just
     295             :  * one interrupt mask/enable bit for all the transcoders.
     296             :  *
     297             :  * Returns the previous state of underrun reporting.
     298             :  */
     299           0 : bool intel_set_pch_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
     300             :                                            enum transcoder pch_transcoder,
     301             :                                            bool enable)
     302             : {
     303           0 :         struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder];
     304           0 :         struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
     305             :         unsigned long flags;
     306             :         bool old;
     307             : 
     308             :         /*
     309             :          * NOTE: Pre-LPT has a fixed cpu pipe -> pch transcoder mapping, but LPT
     310             :          * has only one pch transcoder A that all pipes can use. To avoid racy
     311             :          * pch transcoder -> pipe lookups from interrupt code simply store the
     312             :          * underrun statistics in crtc A. Since we never expose this anywhere
     313             :          * nor use it outside of the fifo underrun code here using the "wrong"
     314             :          * crtc on LPT won't cause issues.
     315             :          */
     316             : 
     317           0 :         spin_lock_irqsave(&dev_priv->irq_lock, flags);
     318             : 
     319           0 :         old = !intel_crtc->pch_fifo_underrun_disabled;
     320           0 :         intel_crtc->pch_fifo_underrun_disabled = !enable;
     321             : 
     322           0 :         if (HAS_PCH_IBX(dev_priv->dev))
     323           0 :                 ibx_set_fifo_underrun_reporting(dev_priv->dev, pch_transcoder,
     324             :                                                 enable);
     325             :         else
     326           0 :                 cpt_set_fifo_underrun_reporting(dev_priv->dev, pch_transcoder,
     327             :                                                 enable, old);
     328             : 
     329           0 :         spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
     330           0 :         return old;
     331             : }
     332             : 
     333             : /**
     334             :  * intel_cpu_fifo_underrun_irq_handler - handle CPU fifo underrun interrupt
     335             :  * @dev_priv: i915 device instance
     336             :  * @pipe: (CPU) pipe to set state for
     337             :  *
     338             :  * This handles a CPU fifo underrun interrupt, generating an underrun warning
     339             :  * into dmesg if underrun reporting is enabled and then disables the underrun
     340             :  * interrupt to avoid an irq storm.
     341             :  */
     342           0 : void intel_cpu_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
     343             :                                          enum pipe pipe)
     344             : {
     345           0 :         struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
     346             : 
     347             :         /* We may be called too early in init, thanks BIOS! */
     348           0 :         if (crtc == NULL)
     349           0 :                 return;
     350             : 
     351             :         /* GMCH can't disable fifo underruns, filter them. */
     352           0 :         if (HAS_GMCH_DISPLAY(dev_priv->dev) &&
     353           0 :             to_intel_crtc(crtc)->cpu_fifo_underrun_disabled)
     354           0 :                 return;
     355             : 
     356           0 :         if (intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false))
     357           0 :                 DRM_ERROR("CPU pipe %c FIFO underrun\n",
     358             :                           pipe_name(pipe));
     359           0 : }
     360             : 
     361             : /**
     362             :  * intel_pch_fifo_underrun_irq_handler - handle PCH fifo underrun interrupt
     363             :  * @dev_priv: i915 device instance
     364             :  * @pch_transcoder: the PCH transcoder (same as pipe on IVB and older)
     365             :  *
     366             :  * This handles a PCH fifo underrun interrupt, generating an underrun warning
     367             :  * into dmesg if underrun reporting is enabled and then disables the underrun
     368             :  * interrupt to avoid an irq storm.
     369             :  */
     370           0 : void intel_pch_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv,
     371             :                                          enum transcoder pch_transcoder)
     372             : {
     373           0 :         if (intel_set_pch_fifo_underrun_reporting(dev_priv, pch_transcoder,
     374             :                                                   false))
     375           0 :                 DRM_ERROR("PCH transcoder %c FIFO underrun\n",
     376             :                           transcoder_name(pch_transcoder));
     377           0 : }

Generated by: LCOV version 1.13