On Wed, Sep 13, 2017 at 07:18:46PM +0100, Chris Wilson wrote: > When handling context-switch interrupts, we are very latency sensitive; > every unnecessary mmio (uncached) read contributes toward a large > decrease in request throughput. An example is gem_exec_whisper, which > ping-pongs between the engines, where avoiding the pipe underflow > checking reduces the runtime of the test from 29s to 22s. On the other > hand, we are now not checking for pipe underflows at 100KHz, more or > less reducing it to a check every pageflip (60Hz) or modeset at worst. > > add/remove: 0/0 grow/shrink: 1/2 up/down: 24/-40 (-16) > function old new delta > valleyview_pipestat_irq_ack 259 283 +24 > valleyview_irq_handler 521 517 -4 > cherryview_irq_handler 457 421 -36 > > Signed-off-by: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx> > Cc: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> > Cc: Mika Kuoppala <mika.kuoppala@xxxxxxxxx> > Cc: Tvrtko Ursulin <tvrtko.ursulin@xxxxxxxxx> > Cc: Joonas Lahtinen <joonas.lahtinen@xxxxxxxxxxxxxxx> > --- > drivers/gpu/drm/i915/i915_irq.c | 123 ++++++++++++++++++++++++---------------- > 1 file changed, 73 insertions(+), 50 deletions(-) > > diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c > index e1d503b7352e..345d73bd4039 100644 > --- a/drivers/gpu/drm/i915/i915_irq.c > +++ b/drivers/gpu/drm/i915/i915_irq.c > @@ -1703,16 +1703,17 @@ static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 gt_iir) > } > } > > -static void valleyview_pipestat_irq_ack(struct drm_i915_private *dev_priv, > +static bool valleyview_pipestat_irq_ack(struct drm_i915_private *dev_priv, > u32 iir, u32 pipe_stats[I915_MAX_PIPES]) > { > + bool handled = false; > int pipe; > > spin_lock(&dev_priv->irq_lock); > > if (!dev_priv->display_irqs_enabled) { > spin_unlock(&dev_priv->irq_lock); > - return; > + return false; > } > > for_each_pipe(dev_priv, pipe) { > @@ -1744,8 +1745,10 @@ static void valleyview_pipestat_irq_ack(struct drm_i915_private *dev_priv, > if (iir & iir_bit) > mask |= dev_priv->pipestat_irq_mask[pipe]; > > - if (!mask) > + if (!mask) { > + pipe_stats[pipe] = 0; > continue; > + } > > reg = PIPESTAT(pipe); > mask |= PIPESTAT_INT_ENABLE_MASK; > @@ -1757,8 +1760,12 @@ static void valleyview_pipestat_irq_ack(struct drm_i915_private *dev_priv, > if (pipe_stats[pipe] & (PIPE_FIFO_UNDERRUN_STATUS | > PIPESTAT_INT_STATUS_MASK)) > I915_WRITE(reg, pipe_stats[pipe]); > + > + handled = true; > } > spin_unlock(&dev_priv->irq_lock); > + > + return handled; > } > > static void valleyview_pipestat_irq_handler(struct drm_i915_private *dev_priv, > @@ -1836,8 +1843,9 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) > > do { > u32 iir, gt_iir, pm_iir; > - u32 pipe_stats[I915_MAX_PIPES] = {}; > + u32 pipe_stats[I915_MAX_PIPES]; > u32 hotplug_status = 0; > + bool has_pipe_stats; > u32 ier = 0; > > gt_iir = I915_READ(GTIIR); > @@ -1876,7 +1884,8 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) > > /* Call regardless, as some status bits might not be > * signalled in iir */ > - valleyview_pipestat_irq_ack(dev_priv, iir, pipe_stats); > + has_pipe_stats = > + valleyview_pipestat_irq_ack(dev_priv, iir, pipe_stats); > > if (iir & (I915_LPE_PIPE_A_INTERRUPT | > I915_LPE_PIPE_B_INTERRUPT)) > @@ -1901,7 +1910,8 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg) > if (hotplug_status) > i9xx_hpd_irq_handler(dev_priv, hotplug_status); > > - valleyview_pipestat_irq_handler(dev_priv, pipe_stats); > + if (has_pipe_stats) > + valleyview_pipestat_irq_handler(dev_priv, pipe_stats); > } while (0); > > enable_rpm_wakeref_asserts(dev_priv); > @@ -1914,27 +1924,14 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg) > struct drm_device *dev = arg; > struct drm_i915_private *dev_priv = to_i915(dev); > irqreturn_t ret = IRQ_NONE; > + u32 master_ctl; > > if (!intel_irqs_enabled(dev_priv)) > return IRQ_NONE; > > - /* IRQs are synced during runtime_suspend, we don't require a wakeref */ > - disable_rpm_wakeref_asserts(dev_priv); > - > + master_ctl = I915_READ_FW(GEN8_MASTER_IRQ); > do { > - u32 master_ctl, iir; > - u32 gt_iir[4] = {}; > - u32 pipe_stats[I915_MAX_PIPES] = {}; > - u32 hotplug_status = 0; > - u32 ier = 0; > - > - master_ctl = I915_READ(GEN8_MASTER_IRQ) & ~GEN8_MASTER_IRQ_CONTROL; > - iir = I915_READ(VLV_IIR); > - > - if (master_ctl == 0 && iir == 0) > - break; > - > - ret = IRQ_HANDLED; > + u32 iir; > > /* > * Theory on interrupt generation, based on empirical evidence: > @@ -1949,44 +1946,70 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg) > * don't end up clearing all the VLV_IIR and GEN8_MASTER_IRQ_CONTROL > * bits this time around. > */ > - I915_WRITE(GEN8_MASTER_IRQ, 0); > - ier = I915_READ(VLV_IER); > - I915_WRITE(VLV_IER, 0); > + if (master_ctl & ~GEN8_MASTER_IRQ_CONTROL) { > + u32 gt_iir[4]; > > - gen8_gt_irq_ack(dev_priv, master_ctl, gt_iir); > + I915_WRITE_FW(GEN8_MASTER_IRQ, 0); > > - if (iir & I915_DISPLAY_PORT_INTERRUPT) > - hotplug_status = i9xx_hpd_irq_ack(dev_priv); > + gen8_gt_irq_ack(dev_priv, master_ctl, gt_iir); > > - /* Call regardless, as some status bits might not be > - * signalled in iir */ > - valleyview_pipestat_irq_ack(dev_priv, iir, pipe_stats); > + I915_WRITE_FW(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL); > + ret = IRQ_HANDLED; I suspect this won't work correctly. If I'm correct on how the edge triggering works we really need to have both MASTER_IRQ_CONTROL and IER disabled at the same time. Otherwise one can prevent the other from generating an edge to the CPU interrupt logic. > > - if (iir & (I915_LPE_PIPE_A_INTERRUPT | > - I915_LPE_PIPE_B_INTERRUPT | > - I915_LPE_PIPE_C_INTERRUPT)) > - intel_lpe_audio_irq_handler(dev_priv); > + gen8_gt_irq_handler(dev_priv, master_ctl, gt_iir); > + master_ctl = 0; > + } > > - /* > - * VLV_IIR is single buffered, and reflects the level > - * from PIPESTAT/PORT_HOTPLUG_STAT, hence clear it last. > - */ > - if (iir) > - I915_WRITE(VLV_IIR, iir); > + iir = I915_READ_FW(VLV_IIR); > + if (iir) { > + u32 pipe_stats[I915_MAX_PIPES]; > + u32 hotplug_status = 0; > + bool has_pipe_stats = false; > + u32 ier; > > - I915_WRITE(VLV_IER, ier); > - I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL); > - POSTING_READ(GEN8_MASTER_IRQ); > + /* > + * IRQs are synced during runtime_suspend, > + * we don't require a wakeref > + */ > + disable_rpm_wakeref_asserts(dev_priv); > > - gen8_gt_irq_handler(dev_priv, master_ctl, gt_iir); > > - if (hotplug_status) > - i9xx_hpd_irq_handler(dev_priv, hotplug_status); > + ier = I915_READ_FW(VLV_IER); > + I915_WRITE_FW(VLV_IER, 0); > > - valleyview_pipestat_irq_handler(dev_priv, pipe_stats); > - } while (0); > + if (iir & I915_DISPLAY_PORT_INTERRUPT) > + hotplug_status = i9xx_hpd_irq_ack(dev_priv); > > - enable_rpm_wakeref_asserts(dev_priv); > + if (iir & (I915_LPE_PIPE_A_INTERRUPT | > + I915_LPE_PIPE_B_INTERRUPT | > + I915_LPE_PIPE_C_INTERRUPT)) > + intel_lpe_audio_irq_handler(dev_priv); > + > + /* > + * Call regardless, as some status bits might not be > + * signalled in iir. > + */ > + has_pipe_stats = > + valleyview_pipestat_irq_ack(dev_priv, iir, pipe_stats); > + > + /* > + * VLV_IIR is single buffered, and reflects the level > + * from PIPESTAT/PORT_HOTPLUG_STAT, hence clear it last. > + */ > + I915_WRITE_FW(VLV_IIR, iir); > + I915_WRITE_FW(VLV_IER, ier); > + ret = IRQ_HANDLED; > + > + if (hotplug_status) > + i9xx_hpd_irq_handler(dev_priv, hotplug_status); > + > + if (has_pipe_stats) > + valleyview_pipestat_irq_handler(dev_priv, pipe_stats); > + > + enable_rpm_wakeref_asserts(dev_priv); > + master_ctl = I915_READ_FW(GEN8_MASTER_IRQ); > + } > + } while (master_ctl & ~GEN8_MASTER_IRQ_CONTROL); > > return ret; > } > -- > 2.14.1 -- Ville Syrjälä Intel OTC _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx