On Mon, Jun 16, 2014 at 04:10:59PM +0100, oscar.ma...@intel.com wrote:
> From: Oscar Mateo <oscar.ma...@intel.com>
> 
> Otherwise, we might receive a new interrupt before we have time to
> ack the first one, eventually missing it.
> 
> The right order should be:
> 
> 1 - Disable Master Interrupt Control.
> 2 - Find the category of interrupt that is pending.
> 3 - Find the source(s) of the interrupt and clear the Interrupt Identity bits 
> (IIR)
> 4 - Process the interrupt(s) that had bits set in the IIRs.
> 5 - Re-enable Master Interrupt Control.
> 
> Without an atomic XCHG operation with mmio space, the above merely reduces 
> the window
> in which we can miss an interrupt (especially when you consider how 
> heavyweight the
> I915_READ/I915_WRITE operations are).
> 
> Spotted by Bob Beckett <robert.beck...@intel.com>.
> 
> v2: Add warning to commit message and comments to the code as per Chris 
> Wilson's request.
> 
> v3: Improve the source code comment.
> 
> Signed-off-by: Oscar Mateo <oscar.ma...@intel.com>

This one had a small conflict with Chris' stall detection patch that I
fixed up while applying. Entire series merged, thanks.
-Daniel

> ---
>  drivers/gpu/drm/i915/i915_irq.c | 91 
> ++++++++++++++++++++---------------------
>  1 file changed, 45 insertions(+), 46 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index 20f7c05..46fe3ad 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -1462,6 +1462,7 @@ static irqreturn_t gen8_gt_irq_handler(struct 
> drm_device *dev,
>       if (master_ctl & (GEN8_GT_RCS_IRQ | GEN8_GT_BCS_IRQ)) {
>               tmp = I915_READ(GEN8_GT_IIR(0));
>               if (tmp) {
> +                     I915_WRITE(GEN8_GT_IIR(0), tmp);
>                       ret = IRQ_HANDLED;
>                       rcs = tmp >> GEN8_RCS_IRQ_SHIFT;
>                       bcs = tmp >> GEN8_BCS_IRQ_SHIFT;
> @@ -1469,7 +1470,6 @@ static irqreturn_t gen8_gt_irq_handler(struct 
> drm_device *dev,
>                               notify_ring(dev, &dev_priv->ring[RCS]);
>                       if (bcs & GT_RENDER_USER_INTERRUPT)
>                               notify_ring(dev, &dev_priv->ring[BCS]);
> -                     I915_WRITE(GEN8_GT_IIR(0), tmp);
>               } else
>                       DRM_ERROR("The master control interrupt lied (GT0)!\n");
>       }
> @@ -1477,6 +1477,7 @@ static irqreturn_t gen8_gt_irq_handler(struct 
> drm_device *dev,
>       if (master_ctl & (GEN8_GT_VCS1_IRQ | GEN8_GT_VCS2_IRQ)) {
>               tmp = I915_READ(GEN8_GT_IIR(1));
>               if (tmp) {
> +                     I915_WRITE(GEN8_GT_IIR(1), tmp);
>                       ret = IRQ_HANDLED;
>                       vcs = tmp >> GEN8_VCS1_IRQ_SHIFT;
>                       if (vcs & GT_RENDER_USER_INTERRUPT)
> @@ -1484,7 +1485,6 @@ static irqreturn_t gen8_gt_irq_handler(struct 
> drm_device *dev,
>                       vcs = tmp >> GEN8_VCS2_IRQ_SHIFT;
>                       if (vcs & GT_RENDER_USER_INTERRUPT)
>                               notify_ring(dev, &dev_priv->ring[VCS2]);
> -                     I915_WRITE(GEN8_GT_IIR(1), tmp);
>               } else
>                       DRM_ERROR("The master control interrupt lied (GT1)!\n");
>       }
> @@ -1492,10 +1492,10 @@ static irqreturn_t gen8_gt_irq_handler(struct 
> drm_device *dev,
>       if (master_ctl & GEN8_GT_PM_IRQ) {
>               tmp = I915_READ(GEN8_GT_IIR(2));
>               if (tmp & dev_priv->pm_rps_events) {
> -                     ret = IRQ_HANDLED;
> -                     gen8_rps_irq_handler(dev_priv, tmp);
>                       I915_WRITE(GEN8_GT_IIR(2),
>                                  tmp & dev_priv->pm_rps_events);
> +                     ret = IRQ_HANDLED;
> +                     gen8_rps_irq_handler(dev_priv, tmp);
>               } else
>                       DRM_ERROR("The master control interrupt lied (PM)!\n");
>       }
> @@ -1503,11 +1503,11 @@ static irqreturn_t gen8_gt_irq_handler(struct 
> drm_device *dev,
>       if (master_ctl & GEN8_GT_VECS_IRQ) {
>               tmp = I915_READ(GEN8_GT_IIR(3));
>               if (tmp) {
> +                     I915_WRITE(GEN8_GT_IIR(3), tmp);
>                       ret = IRQ_HANDLED;
>                       vcs = tmp >> GEN8_VECS_IRQ_SHIFT;
>                       if (vcs & GT_RENDER_USER_INTERRUPT)
>                               notify_ring(dev, &dev_priv->ring[VECS]);
> -                     I915_WRITE(GEN8_GT_IIR(3), tmp);
>               } else
>                       DRM_ERROR("The master control interrupt lied (GT3)!\n");
>       }
> @@ -2238,36 +2238,36 @@ static irqreturn_t gen8_irq_handler(int irq, void 
> *arg)
>       I915_WRITE(GEN8_MASTER_IRQ, 0);
>       POSTING_READ(GEN8_MASTER_IRQ);
>  
> +     /* Find, clear, then process each source of interrupt */
> +
>       ret = gen8_gt_irq_handler(dev, dev_priv, master_ctl);
>  
>       if (master_ctl & GEN8_DE_MISC_IRQ) {
>               tmp = I915_READ(GEN8_DE_MISC_IIR);
> -             if (tmp & GEN8_DE_MISC_GSE)
> -                     intel_opregion_asle_intr(dev);
> -             else if (tmp)
> -                     DRM_ERROR("Unexpected DE Misc interrupt\n");
> -             else
> -                     DRM_ERROR("The master control interrupt lied (DE 
> MISC)!\n");
> -
>               if (tmp) {
>                       I915_WRITE(GEN8_DE_MISC_IIR, tmp);
>                       ret = IRQ_HANDLED;
> +                     if (tmp & GEN8_DE_MISC_GSE)
> +                             intel_opregion_asle_intr(dev);
> +                     else
> +                             DRM_ERROR("Unexpected DE Misc interrupt\n");
>               }
> +             else
> +                     DRM_ERROR("The master control interrupt lied (DE 
> MISC)!\n");
>       }
>  
>       if (master_ctl & GEN8_DE_PORT_IRQ) {
>               tmp = I915_READ(GEN8_DE_PORT_IIR);
> -             if (tmp & GEN8_AUX_CHANNEL_A)
> -                     dp_aux_irq_handler(dev);
> -             else if (tmp)
> -                     DRM_ERROR("Unexpected DE Port interrupt\n");
> -             else
> -                     DRM_ERROR("The master control interrupt lied (DE 
> PORT)!\n");
> -
>               if (tmp) {
>                       I915_WRITE(GEN8_DE_PORT_IIR, tmp);
>                       ret = IRQ_HANDLED;
> +                     if (tmp & GEN8_AUX_CHANNEL_A)
> +                             dp_aux_irq_handler(dev);
> +                     else
> +                             DRM_ERROR("Unexpected DE Port interrupt\n");
>               }
> +             else
> +                     DRM_ERROR("The master control interrupt lied (DE 
> PORT)!\n");
>       }
>  
>       for_each_pipe(pipe) {
> @@ -2277,33 +2277,32 @@ static irqreturn_t gen8_irq_handler(int irq, void 
> *arg)
>                       continue;
>  
>               pipe_iir = I915_READ(GEN8_DE_PIPE_IIR(pipe));
> -             if (pipe_iir & GEN8_PIPE_VBLANK)
> -                     intel_pipe_handle_vblank(dev, pipe);
> -
> -             if (pipe_iir & GEN8_PIPE_PRIMARY_FLIP_DONE) {
> -                     intel_prepare_page_flip(dev, pipe);
> -                     intel_finish_page_flip_plane(dev, pipe);
> -             }
> +             if (pipe_iir) {
> +                     ret = IRQ_HANDLED;
> +                     I915_WRITE(GEN8_DE_PIPE_IIR(pipe), pipe_iir);
> +                     if (pipe_iir & GEN8_PIPE_VBLANK)
> +                             intel_pipe_handle_vblank(dev, pipe);
>  
> -             if (pipe_iir & GEN8_PIPE_CDCLK_CRC_DONE)
> -                     hsw_pipe_crc_irq_handler(dev, pipe);
> +                     if (pipe_iir & GEN8_PIPE_PRIMARY_FLIP_DONE) {
> +                             intel_prepare_page_flip(dev, pipe);
> +                             intel_finish_page_flip_plane(dev, pipe);
> +                     }
>  
> -             if (pipe_iir & GEN8_PIPE_FIFO_UNDERRUN) {
> -                     if (intel_set_cpu_fifo_underrun_reporting(dev, pipe,
> -                                                               false))
> -                             DRM_ERROR("Pipe %c FIFO underrun\n",
> -                                       pipe_name(pipe));
> -             }
> +                     if (pipe_iir & GEN8_PIPE_CDCLK_CRC_DONE)
> +                             hsw_pipe_crc_irq_handler(dev, pipe);
>  
> -             if (pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS) {
> -                     DRM_ERROR("Fault errors on pipe %c\n: 0x%08x",
> -                               pipe_name(pipe),
> -                               pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS);
> -             }
> +                     if (pipe_iir & GEN8_PIPE_FIFO_UNDERRUN) {
> +                             if (intel_set_cpu_fifo_underrun_reporting(dev, 
> pipe,
> +                                                                       
> false))
> +                                     DRM_ERROR("Pipe %c FIFO underrun\n",
> +                                               pipe_name(pipe));
> +                     }
>  
> -             if (pipe_iir) {
> -                     ret = IRQ_HANDLED;
> -                     I915_WRITE(GEN8_DE_PIPE_IIR(pipe), pipe_iir);
> +                     if (pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS) {
> +                             DRM_ERROR("Fault errors on pipe %c\n: 0x%08x",
> +                                       pipe_name(pipe),
> +                                       pipe_iir & 
> GEN8_DE_PIPE_IRQ_FAULT_ERRORS);
> +                     }
>               } else
>                       DRM_ERROR("The master control interrupt lied (DE 
> PIPE)!\n");
>       }
> @@ -2315,13 +2314,13 @@ static irqreturn_t gen8_irq_handler(int irq, void 
> *arg)
>                * on older pch-split platforms. But this needs testing.
>                */
>               u32 pch_iir = I915_READ(SDEIIR);
> -
> -             cpt_irq_handler(dev, pch_iir);
> -
>               if (pch_iir) {
>                       I915_WRITE(SDEIIR, pch_iir);
>                       ret = IRQ_HANDLED;
> -             }
> +                     cpt_irq_handler(dev, pch_iir);
> +             } else
> +                     DRM_ERROR("The master control interrupt lied (SDE)!\n");
> +
>       }
>  
>       I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
> -- 
> 1.9.0
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@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
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to