[Intel-gfx] [PATCH 2/4] drm/i915: report Gen5+ CPU and PCH FIFO underruns

Paulo Zanoni przanoni at gmail.com
Fri Apr 12 22:05:25 CEST 2013


Hi

2013/3/28 Daniel Vetter <daniel at ffwll.ch>:
> On Fri, Feb 22, 2013 at 05:05:29PM -0300, Paulo Zanoni wrote:
>> From: Paulo Zanoni <paulo.r.zanoni at intel.com>
>>
>> In this commit we enable both CPU and PCH FIFO underrun reporting and
>> start reporting them. We follow a few rules:
>>   - after we receive one of these errors, we mask the interrupt, so
>>     we won't get an "interrupt storm" and we also won't flood dmesg;
>>   - at each mode set we enable the interrupts again, so we'll see each
>>     message at most once per mode set;
>>   - in the specific places where we need to ignore the errors, we
>>     completely mask the interrupts.
>>
>> The downside of this patch is that since we're completely disabling
>> (masking) the interrupts instead of just not printing error messages,
>> we will mask more than just what we want on IVB/HSW CPU interrupts
>> (due to GEN7_ERR_INT) and on CPT/PPT/LPT PCHs (due to SERR_INT). So
>> when we decide to mask PCH FIFO underruns for pipe A on CPT, we'll
>> also be masking PCH FIFO underruns for pipe B, because both are
>> reported by SERR_INT which has to be either completely enabled or
>> completely disabled (in othe words, there's no way to disable/enable
>> specific bits of GEN7_ERR_INT and SERR_INT).
>>
>> Signed-off-by: Paulo Zanoni <paulo.r.zanoni at intel.com>
>
> Ok, sorry for the long delay in reviewing this (I've somehow hoped that
> someone else would do it, but meh ...).
>
> I'm happy with the logic in your patch here, but it took me a while to
> piece together the control flow and what exactly is done where. I think
> that can be improved by renaming a few functions to make it clearer what
> exactly they're doing. Suggestions below.

Yeah, looks like the names were not really good. See below.


>
> The only functional comment is about the hsw err irq blocking, at least to
> me it looks not required.
>
> Yours, Daniel
>
>> ---
>>  drivers/gpu/drm/i915/i915_irq.c      |  307 +++++++++++++++++++++++++++++++++-
>>  drivers/gpu/drm/i915/i915_reg.h      |   13 +-
>>  drivers/gpu/drm/i915/intel_display.c |   17 +-
>>  drivers/gpu/drm/i915/intel_drv.h     |   10 ++
>>  4 files changed, 334 insertions(+), 13 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
>> index 7531095..d0f9c47 100644
>> --- a/drivers/gpu/drm/i915/i915_irq.c
>> +++ b/drivers/gpu/drm/i915/i915_irq.c
>> @@ -57,6 +57,208 @@ ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
>>       }
>>  }
>>
>> +static bool disable_gen7_err_int(struct drm_i915_private *dev_priv)
>
> It took me a while to figure out that this just checks whether underrun
> reporting is disabled on any crtc and whether we hence need to disable it
> completely. Usually I presume that a function call verb_something actually
> does what the verb say, e.g. disable_foo I expect that the function
> actually disables foo.
>
> Since I can't come up with a concise name for these two functions here
> (have_pipe_with_disabled_underrun_reporting is the best I could do ...)
> maybe just inline it into their respective (only) callsite and add a
> comment before the loop saying what it does? Maybe like
>
>         bool can_enable_underrun_reporting = true;
>
>         /* No per-crtc underrun irq disable bit, only a global one. */
>         for_each_pipe {
>                 if (crtc->underrun_reporting_disabled)
>                         can_enable_underrun_reporting = false;
>         }
>
>         if (enable && can_enable_underrun_reporting)
>                 /* enable */
>         else
>                 /* disable */

I renamed disable_gen7_err_int() to ivb_can_enable_err_int() (and
inverted its behavior, of course). Same thing with
cpt_can_enable_serr_int(). I hope it's understandable now :)

>> +{
>> +     struct intel_crtc *crtc;
>> +     enum pipe pipe;
>> +
>> +     for_each_pipe(pipe) {
>> +             crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
>> +
>> +             if (crtc->disable_cpu_fifo_underrun)
>
> Same here, I'd go with cpu_fifo_underrun_disabled to make it clear that
> it's a state tracking, not a request/action variable.

Done.

>
>> +                     return true;
>> +     }
>> +
>> +     return false;
>> +}
>> +
>> +static bool disable_serr_int(struct drm_i915_private *dev_priv)
>> +{
>> +     enum pipe pipe;
>> +     struct intel_crtc *crtc;
>> +
>> +     for_each_pipe(pipe) {
>> +             crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
>> +
>> +             if (crtc->disable_pch_fifo_underrun)
>> +                     return true;
>> +     }
>> +
>> +     return false;
>> +}
>> +
>> +static void ironlake_report_fifo_underrun(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_report_fifo_underrun(struct drm_device *dev, bool enable)
>> +{
>> +     struct drm_i915_private *dev_priv = dev->dev_private;
>> +
>> +     if (enable) {
>> +             if (disable_gen7_err_int(dev_priv))
>> +                     return;
>> +
>> +             I915_WRITE(GEN7_ERR_INT, ERR_INT_FIFO_UNDERRUN_A |
>> +                                      ERR_INT_FIFO_UNDERRUN_B |
>> +                                      ERR_INT_FIFO_UNDERRUN_C);
>> +
>> +             ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
>> +     } else {
>> +             ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
>> +     }
>> +}
>> +
>> +static void ibx_report_fifo_underrun(struct intel_crtc *crtc, bool enable)
>> +{
>> +     struct drm_device *dev = crtc->base.dev;
>> +     struct drm_i915_private *dev_priv = dev->dev_private;
>> +     uint32_t bit = (crtc->pipe == PIPE_A) ? SDE_TRANSA_FIFO_UNDER :
>> +                                             SDE_TRANSB_FIFO_UNDER;
>> +
>> +     if (enable)
>> +             I915_WRITE(SDEIMR, I915_READ(SDEIMR) & ~bit);
>> +     else
>> +             I915_WRITE(SDEIMR, I915_READ(SDEIMR) | bit);
>> +
>> +     POSTING_READ(SDEIMR);
>> +}
>> +
>> +static void cpt_report_fifo_underrun(struct drm_device *dev,
>> +                                  enum transcoder pch_transcoder,
>> +                                  bool enable)
>> +{
>> +     struct drm_i915_private *dev_priv = dev->dev_private;
>> +
>> +     if (enable) {
>> +             if (disable_serr_int(dev_priv))
>> +                     return;
>> +
>> +             I915_WRITE(SERR_INT, SERR_INT_TRANS_A_FIFO_UNDERRUN |
>> +                                  SERR_INT_TRANS_B_FIFO_UNDERRUN |
>> +                                  SERR_INT_TRANS_C_FIFO_UNDERRUN);
>> +
>> +             I915_WRITE(SDEIMR, I915_READ(SDEIMR) & ~SDE_ERROR_CPT);
>> +     } else {
>> +             I915_WRITE(SDEIMR, I915_READ(SDEIMR) | SDE_ERROR_CPT);
>> +     }
>> +
>> +     POSTING_READ(SDEIMR);
>> +}
>> +
>> +/**
>> + * intel_report_cpu_fifo_underrun - 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 report CPU fifo underruns for a specific
>
> "disable or enable" (instead of report) is imo clearer, see below.

Done.

>
>> + * 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.
>> + */
>> +bool intel_report_cpu_fifo_underrun(struct drm_device *dev, enum pipe pipe,
>> +                                 bool enable)
>
> Again I've tripped up about the report verb, presuming that this function
> reports underruns. But it only updates the underrun reporting state, so
> maybe intel_*_fifo_underrun_reporting?

Changed to intel_set_{cpu,pch}_fifo_underrun_reporting.

>
>> +{
>> +     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);
>> +     unsigned long flags;
>> +     bool ret;
>> +
>> +     spin_lock_irqsave(&dev_priv->irq_lock, flags);
>> +
>> +     ret = !intel_crtc->disable_cpu_fifo_underrun;
>> +
>> +     if (enable == ret)
>> +             goto done;
>> +
>> +     intel_crtc->disable_cpu_fifo_underrun = !enable;
>> +
>> +     if (IS_GEN5(dev) || IS_GEN6(dev))
>> +             ironlake_report_fifo_underrun(dev, pipe, enable);
>> +     else if (IS_GEN7(dev))
>> +             ivybridge_report_fifo_underrun(dev, enable);
>> +
>> +done:
>> +     spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
>> +     return ret;
>> +}
>> +
>> +/**
>> + * intel_report_pch_fifo_underrun - 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 report 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_report_pch_fifo_underrun(struct drm_device *dev,
>> +                                 enum transcoder pch_transcoder,
>> +                                 bool enable)
>> +{
>> +     struct drm_i915_private *dev_priv = dev->dev_private;
>> +     enum pipe p;
>> +     struct drm_crtc *crtc;
>> +     struct intel_crtc *intel_crtc;
>> +     unsigned long flags;
>> +     bool ret;
>> +
>> +     if (HAS_PCH_LPT(dev)) {
>> +             crtc = NULL;
>> +             for_each_pipe(p) {
>> +                     struct drm_crtc *c = dev_priv->pipe_to_crtc_mapping[p];
>> +                     if (intel_pipe_has_type(c, INTEL_OUTPUT_ANALOG)) {
>> +                             crtc = c;
>> +                             break;
>> +                     }
>> +             }
>> +             if (!crtc) {
>> +                     DRM_ERROR("PCH FIFO underrun, but no CRTC using the PCH found\n");
>> +                     return false;
>> +             }
>> +     } else {
>> +             crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder];
>> +     }
>> +     intel_crtc = to_intel_crtc(crtc);
>> +
>> +     spin_lock_irqsave(&dev_priv->irq_lock, flags);
>> +
>> +     ret = !intel_crtc->disable_pch_fifo_underrun;
>> +
>> +     if (enable == ret)
>> +             goto done;
>> +
>> +     intel_crtc->disable_pch_fifo_underrun = !enable;
>> +
>> +     if (HAS_PCH_IBX(dev))
>> +             ibx_report_fifo_underrun(intel_crtc, enable);
>> +     else
>> +             cpt_report_fifo_underrun(dev, pch_transcoder, enable);
>> +
>> +done:
>> +     spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
>> +     return ret;
>> +}
>> +
>>  void
>>  i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
>>  {
>> @@ -659,14 +861,57 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
>>       if (pch_iir & (SDE_TRANSB_CRC_ERR | SDE_TRANSA_CRC_ERR))
>>               DRM_DEBUG_DRIVER("PCH transcoder CRC error interrupt\n");
>>
>> -     if (pch_iir & SDE_TRANSB_FIFO_UNDER)
>> -             DRM_DEBUG_DRIVER("PCH transcoder B underrun interrupt\n");
>>       if (pch_iir & SDE_TRANSA_FIFO_UNDER)
>> -             DRM_DEBUG_DRIVER("PCH transcoder A underrun interrupt\n");
>> +             if (intel_report_pch_fifo_underrun(dev, TRANSCODER_A, false))
>> +                     DRM_ERROR("PCH transcoder A FIFO underrun\n");
>
> It sounds like we have outstanding issues with underruns still, but I'd
> like to merge your patch sooner than later (it looks like the kind with
> massive rebase pain). So keep things at DRM_DEBUG_DRIVER meanwhile, until
> we've fixed the know ones?

Done. Let's see what happens when we ship this :)

>
>> +
>> +     if (pch_iir & SDE_TRANSB_FIFO_UNDER)
>> +             if (intel_report_pch_fifo_underrun(dev, TRANSCODER_B, false))
>> +                     DRM_ERROR("PCH transcoder B FIFO underrun\n");
>>  }
>>
>> +static void err_int_handler(struct drm_device *dev)
>
> snb_ prefix should be added imo.

Done. It's actually ivb_.

>
>> +{
>> +     struct drm_i915_private *dev_priv = dev->dev_private;
>> +     u32 err_int = I915_READ(GEN7_ERR_INT);
>> +
>> +     if (err_int & ERR_INT_FIFO_UNDERRUN_A)
>> +             if (intel_report_cpu_fifo_underrun(dev, PIPE_A, false))
>> +                     DRM_ERROR("Pipe A FIFO underrun\n");
>> +
>> +     if (err_int & ERR_INT_FIFO_UNDERRUN_B)
>> +             if (intel_report_cpu_fifo_underrun(dev, PIPE_B, false))
>> +                     DRM_ERROR("Pipe B FIFO underrun\n");
>> +
>> +     if (err_int & ERR_INT_FIFO_UNDERRUN_C)
>> +             if (intel_report_cpu_fifo_underrun(dev, PIPE_C, false))
>> +                     DRM_ERROR("Pipe C FIFO underrun\n");
>> +
>> +     I915_WRITE(GEN7_ERR_INT, err_int);
>> +}
>> +
>> +static void serr_int_handler(struct drm_device *dev)
>
> Same here for an cpt_ prefix.

Done.

>
>> +{
>> +     struct drm_i915_private *dev_priv = dev->dev_private;
>> +     u32 serr_int = I915_READ(SERR_INT);
>> +
>> +     if (serr_int & SERR_INT_TRANS_A_FIFO_UNDERRUN)
>> +             if (intel_report_pch_fifo_underrun(dev, TRANSCODER_A, false))
>> +                     DRM_ERROR("PCH transcoder A FIFO underrun\n");
>> +
>> +     if (serr_int & SERR_INT_TRANS_B_FIFO_UNDERRUN)
>> +             if (intel_report_pch_fifo_underrun(dev, TRANSCODER_B, false))
>> +                     DRM_ERROR("PCH transcoder B FIFO underrun\n");
>> +
>> +     if (serr_int & SERR_INT_TRANS_C_FIFO_UNDERRUN)
>> +             if (intel_report_pch_fifo_underrun(dev, TRANSCODER_C, false))
>> +                     DRM_ERROR("PCH transcoder C FIFO underrun\n");
>> +
>> +     I915_WRITE(SERR_INT, serr_int);
>> +}
>>  static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
>>  {
>> +
>>       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
>>       int pipe;
>>
>> @@ -695,6 +940,9 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
>>                       DRM_DEBUG_DRIVER("  pipe %c FDI IIR: 0x%08x\n",
>>                                        pipe_name(pipe),
>>                                        I915_READ(FDI_RX_IIR(pipe)));
>> +
>> +     if (pch_iir & SDE_ERROR_CPT)
>> +             serr_int_handler(dev);
>>  }
>>
>>  static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
>> @@ -707,6 +955,14 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
>>
>>       atomic_inc(&dev_priv->irq_received);
>>
>> +     /* We get interrupts on unclaimed registers, so check for this before we
>> +      * do any I915_{READ,WRITE}. */
>> +     if (IS_HASWELL(dev) &&
>> +         (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) {
>> +             DRM_ERROR("Unclaimed register before interrupt\n");
>> +             I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
>> +     }
>> +
>>       /* disable master interrupt before clearing iir  */
>>       de_ier = I915_READ(DEIER);
>>       I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
>> @@ -720,6 +976,12 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
>>       I915_WRITE(SDEIER, 0);
>>       POSTING_READ(SDEIER);
>>
>> +     /* On Haswell, also mask ERR_INT because we don't want to risk
>> +      * generating "unclaimed register" interrupts from inside the interrupt
>> +      * handler. */
>> +     if (IS_HASWELL(dev))
>> +             ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
>
> The above two chunks look like they've escaped from your unclaimed
> register series. Do we still need those?

Yes. We're enabling GEN7_ERR_INT on this patch, so now whenever we
poke an unclaimed register we'll get an interrupt. The good thing is
that this shouldn't be happening with our default configs :)

>
> Imo if we manage to create an unclaimed register interrupt in the irq
> handler, we deserve it. And the linux irq subsystem already ensures that a
> given irq handler can't run in parallel (if another irq fires while it's
> running, an immediate 2nd run is enqueued).

As far as I remember, depending on the case we may keep running irq
handlers forever. Also, we'll still print error messages about
unclaimed registers due to the FPGA_DBG register, so it's not like
errors will go unnoticed :)

I also added the comment suggested on your other email. Thanks for the review :)
<snip>

>
>> +
>>       gt_iir = I915_READ(GTIIR);
>>       if (gt_iir) {
>>               snb_gt_irq_handler(dev, dev_priv, gt_iir);
>> @@ -729,6 +991,9 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
>>
>>       de_iir = I915_READ(DEIIR);
>>       if (de_iir) {
>> +             if (de_iir & DE_ERR_INT_IVB)
>> +                     err_int_handler(dev);
>> +
>>               if (de_iir & DE_AUX_CHANNEL_A_IVB)
>>                       dp_aux_irq_handler(dev);
>>
>> @@ -766,6 +1031,9 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
>>               ret = IRQ_HANDLED;
>>       }
>>
>> +     if (IS_HASWELL(dev) && !disable_gen7_err_int(dev_priv))
>> +             ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
>> +
>>       I915_WRITE(DEIER, de_ier);
>>       POSTING_READ(DEIER);
>>       I915_WRITE(SDEIER, sde_ier);
>> @@ -833,6 +1101,14 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
>>       if (de_iir & DE_PIPEB_VBLANK)
>>               drm_handle_vblank(dev, 1);
>>
>> +     if (de_iir & DE_PIPEA_FIFO_UNDERRUN)
>> +             if (intel_report_cpu_fifo_underrun(dev, PIPE_A, false))
>> +                     DRM_ERROR("Pipe A FIFO underrun\n");
>> +
>> +     if (de_iir & DE_PIPEB_FIFO_UNDERRUN)
>> +             if (intel_report_cpu_fifo_underrun(dev, PIPE_B, false))
>> +                     DRM_ERROR("Pipe B FIFO underrun\n");
>> +
>>       if (de_iir & DE_PLANEA_FLIP_DONE) {
>>               intel_prepare_page_flip(dev, 0);
>>               intel_finish_page_flip_plane(dev, 0);
>> @@ -1966,14 +2242,20 @@ static void ibx_irq_postinstall(struct drm_device *dev)
>>       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
>>       u32 mask;
>>
>> -     if (HAS_PCH_IBX(dev))
>> +     if (HAS_PCH_IBX(dev)) {
>>               mask = SDE_HOTPLUG_MASK |
>>                      SDE_GMBUS |
>> -                    SDE_AUX_MASK;
>> -     else
>> +                    SDE_AUX_MASK |
>> +                    SDE_TRANSB_FIFO_UNDER |
>> +                    SDE_TRANSA_FIFO_UNDER;
>> +     } else {
>>               mask = SDE_HOTPLUG_MASK_CPT |
>>                      SDE_GMBUS_CPT |
>> -                    SDE_AUX_MASK_CPT;
>> +                    SDE_AUX_MASK_CPT |
>> +                    SDE_ERROR_CPT;
>> +
>> +             I915_WRITE(SERR_INT, I915_READ(SERR_INT));
>> +     }
>>
>>       I915_WRITE(SDEIIR, I915_READ(SDEIIR));
>>       I915_WRITE(SDEIMR, ~mask);
>> @@ -1989,7 +2271,8 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
>>       /* enable kind of interrupts always enabled */
>>       u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
>>                          DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE |
>> -                        DE_AUX_CHANNEL_A;
>> +                        DE_AUX_CHANNEL_A | DE_PIPEB_FIFO_UNDERRUN |
>> +                        DE_PIPEA_FIFO_UNDERRUN;
>>       u32 render_irqs;
>>
>>       dev_priv->irq_mask = ~display_mask;
>> @@ -2039,12 +2322,14 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
>>               DE_PLANEC_FLIP_DONE_IVB |
>>               DE_PLANEB_FLIP_DONE_IVB |
>>               DE_PLANEA_FLIP_DONE_IVB |
>> -             DE_AUX_CHANNEL_A_IVB;
>> +             DE_AUX_CHANNEL_A_IVB |
>> +             DE_ERR_INT_IVB;
>>       u32 render_irqs;
>>
>>       dev_priv->irq_mask = ~display_mask;
>>
>>       /* should always can generate irq */
>> +     I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT));
>>       I915_WRITE(DEIIR, I915_READ(DEIIR));
>>       I915_WRITE(DEIMR, dev_priv->irq_mask);
>>       I915_WRITE(DEIER,
>> @@ -2195,6 +2480,8 @@ static void ironlake_irq_uninstall(struct drm_device *dev)
>>       I915_WRITE(DEIMR, 0xffffffff);
>>       I915_WRITE(DEIER, 0x0);
>>       I915_WRITE(DEIIR, I915_READ(DEIIR));
>> +     if (IS_GEN7(dev))
>> +             I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT));
>>
>>       I915_WRITE(GTIMR, 0xffffffff);
>>       I915_WRITE(GTIER, 0x0);
>> @@ -2203,6 +2490,8 @@ static void ironlake_irq_uninstall(struct drm_device *dev)
>>       I915_WRITE(SDEIMR, 0xffffffff);
>>       I915_WRITE(SDEIER, 0x0);
>>       I915_WRITE(SDEIIR, I915_READ(SDEIIR));
>> +     if (HAS_PCH_CPT(dev) || HAS_PCH_LPT(dev))
>> +             I915_WRITE(SERR_INT, I915_READ(SERR_INT));
>>  }
>>
>>  static void i8xx_irq_preinstall(struct drm_device * dev)
>> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
>> index cd226c2..4d27320 100644
>> --- a/drivers/gpu/drm/i915/i915_reg.h
>> +++ b/drivers/gpu/drm/i915/i915_reg.h
>> @@ -520,7 +520,10 @@
>>
>>  #define ERROR_GEN6   0x040a0
>>  #define GEN7_ERR_INT 0x44040
>> -#define   ERR_INT_MMIO_UNCLAIMED (1<<13)
>> +#define   ERR_INT_MMIO_UNCLAIMED     (1<<13)
>> +#define   ERR_INT_FIFO_UNDERRUN_C    (1<<6)
>> +#define   ERR_INT_FIFO_UNDERRUN_B    (1<<3)
>> +#define   ERR_INT_FIFO_UNDERRUN_A    (1<<0)
>>
>>  #define FPGA_DBG             0x42300
>>  #define   FPGA_DBG_RM_NOCLAIM        (1<<31)
>> @@ -3390,7 +3393,7 @@
>>  #define DE_PIPEA_FIFO_UNDERRUN  (1 << 0)
>>
>>  /* More Ivybridge lolz */
>> -#define DE_ERR_DEBUG_IVB             (1<<30)
>> +#define DE_ERR_INT_IVB                       (1<<30)
>>  #define DE_GSE_IVB                   (1<<29)
>>  #define DE_PCH_EVENT_IVB             (1<<28)
>>  #define DE_DP_A_HOTPLUG_IVB          (1<<27)
>> @@ -3540,6 +3543,7 @@
>>                                SDE_PORTC_HOTPLUG_CPT |        \
>>                                SDE_PORTB_HOTPLUG_CPT)
>>  #define SDE_GMBUS_CPT                (1 << 17)
>> +#define SDE_ERROR_CPT                (1 << 16)
>>  #define SDE_AUDIO_CP_REQ_C_CPT       (1 << 10)
>>  #define SDE_AUDIO_CP_CHG_C_CPT       (1 << 9)
>>  #define SDE_FDI_RXC_CPT              (1 << 8)
>> @@ -3564,6 +3568,11 @@
>>  #define SDEIIR  0xc4008
>>  #define SDEIER  0xc400c
>>
>> +#define SERR_INT                     0xc4040
>> +#define  SERR_INT_TRANS_C_FIFO_UNDERRUN      (1<<6)
>> +#define  SERR_INT_TRANS_B_FIFO_UNDERRUN      (1<<3)
>> +#define  SERR_INT_TRANS_A_FIFO_UNDERRUN      (1<<0)
>> +
>>  /* digital port hotplug */
>>  #define PCH_PORT_HOTPLUG        0xc4030              /* SHOTPLUG_CTL */
>>  #define PORTD_HOTPLUG_ENABLE            (1 << 20)
>> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
>> index 9b0cd86..7152f35 100644
>> --- a/drivers/gpu/drm/i915/intel_display.c
>> +++ b/drivers/gpu/drm/i915/intel_display.c
>> @@ -41,7 +41,6 @@
>>  #include <drm/drm_crtc_helper.h>
>>  #include <linux/dma_remapping.h>
>>
>> -bool intel_pipe_has_type(struct drm_crtc *crtc, int type);
>>  static void intel_increase_pllclock(struct drm_crtc *crtc);
>>  static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on);
>>
>> @@ -3305,6 +3304,10 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
>>               return;
>>
>>       intel_crtc->active = true;
>> +
>> +     intel_report_cpu_fifo_underrun(dev, pipe, true);
>> +     intel_report_pch_fifo_underrun(dev, pipe, true);
>> +
>>       intel_update_watermarks(dev);
>>
>>       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
>> @@ -3397,10 +3400,15 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
>>               return;
>>
>>       intel_crtc->active = true;
>> -     intel_update_watermarks(dev);
>>
>>       is_pch_port = haswell_crtc_driving_pch(crtc);
>>
>> +     intel_report_cpu_fifo_underrun(dev, pipe, true);
>> +     if (is_pch_port)
>> +             intel_report_pch_fifo_underrun(dev, TRANSCODER_A, true);
>> +
>> +     intel_update_watermarks(dev);
>> +
>>       if (is_pch_port)
>>               dev_priv->display.fdi_link_train(crtc);
>>
>> @@ -3484,6 +3492,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
>>       if (dev_priv->cfb_plane == plane)
>>               intel_disable_fbc(dev);
>>
>> +     intel_report_pch_fifo_underrun(dev, pipe, false);
>>       intel_disable_pipe(dev_priv, pipe);
>>
>>       /* Disable PF */
>> @@ -3497,6 +3506,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
>>       ironlake_fdi_disable(crtc);
>>
>>       ironlake_disable_pch_transcoder(dev_priv, pipe);
>> +     intel_report_pch_fifo_underrun(dev, pipe, true);
>>
>>       if (HAS_PCH_CPT(dev)) {
>>               /* disable TRANS_DP_CTL */
>> @@ -3566,6 +3576,8 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
>>       if (dev_priv->cfb_plane == plane)
>>               intel_disable_fbc(dev);
>>
>> +     if (is_pch_port)
>> +             intel_report_pch_fifo_underrun(dev, TRANSCODER_A, false);
>>       intel_disable_pipe(dev_priv, pipe);
>>
>>       intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder);
>> @@ -3582,6 +3594,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
>>
>>       if (is_pch_port) {
>>               lpt_disable_pch_transcoder(dev_priv);
>> +             intel_report_pch_fifo_underrun(dev, TRANSCODER_A, true);
>>               intel_ddi_fdi_disable(crtc);
>>       }
>>
>> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
>> index 010e998..aa8f948 100644
>> --- a/drivers/gpu/drm/i915/intel_drv.h
>> +++ b/drivers/gpu/drm/i915/intel_drv.h
>> @@ -238,6 +238,9 @@ struct intel_crtc {
>>
>>       /* reset counter value when the last flip was submitted */
>>       unsigned int reset_counter;
>> +
>> +     bool disable_cpu_fifo_underrun;
>> +     bool disable_pch_fifo_underrun;
>>  };
>>
>>  struct intel_plane {
>> @@ -442,6 +445,7 @@ int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter);
>>  extern void intel_attach_force_audio_property(struct drm_connector *connector);
>>  extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector);
>>
>> +extern bool intel_pipe_has_type(struct drm_crtc *crtc, int type);
>>  extern void intel_crt_init(struct drm_device *dev);
>>  extern void intel_hdmi_init(struct drm_device *dev,
>>                           int hdmi_reg, enum port port);
>> @@ -697,5 +701,11 @@ intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector);
>>  extern void intel_ddi_fdi_disable(struct drm_crtc *crtc);
>>
>>  extern void intel_display_handle_reset(struct drm_device *dev);
>> +extern bool intel_report_cpu_fifo_underrun(struct drm_device *dev,
>> +                                        enum pipe pipe,
>> +                                        bool enable);
>> +extern bool intel_report_pch_fifo_underrun(struct drm_device *dev,
>> +                                        enum transcoder pch_transcoder,
>> +                                        bool enable);
>>
>>  #endif /* __INTEL_DRV_H__ */
>> --
>> 1.7.10.4
>>
>> _______________________________________________
>> Intel-gfx mailing list
>> Intel-gfx at lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch



--
Paulo Zanoni



More information about the Intel-gfx mailing list