Message ID | 20180405140052.10682-4-mika.kuoppala@linux.intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 4/5/2018 7:00 AM, Mika Kuoppala wrote: > From: Oscar Mateo <oscar.mateo@intel.com> > > BSpec says: > > "Second level interrupt events are stored in the GT INT DW. GT INT DW is > a double buffered structure. A snapshot of events is taken when SW reads > GT INT DW. From the time of read to the time of SW completely clearing > GT INT DW (to indicate end of service), all incoming interrupts are logged > in a secondary storage structure. this guarantees that the record of > interrupts SW is servicing will not change while under service". > > We read GT INT DW in several places now: > > - The IRQ handler (banks 0 and 1) where, hopefully, it is completely > cleared (operation now covered with the irq lock). > - The 'reset' interrupts functions for RPS and GuC logs, where we clear > the bit we are interested in and leave the others for the normal > interrupt handler. > - The 'enable' interrupts functions for RPS and GuC logs, as a measure > of precaution. Here we could relax a bit and don't check GT INT DW > at all or, if we do, at least we should clear the offending bit > (which is what this patch does). > > Note that, if every bit is cleared on reading GT INT DW, the register > won't be locked. Also note that, according to the BSpec, GT INT DW > cannot be cleared without first servicing the Selector & Shared IIR > registers. > > v2: > - Remove some code duplication (Tvrtko) > - Make sure GT_INTR_DW are protected by the irq spinlock, since it's a > global resource (Tvrtko) > > v3: Optimize the spinlock (Tvrtko) > > v4: Rebase. > v5: > - take spinlock on outer scope to please sparse (Mika) > - use raw_reg accessors (Mika) > > Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> > Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> > Cc: Sagar Arun Kamble <sagar.a.kamble@intel.com> > Signed-off-by: Oscar Mateo <oscar.mateo@intel.com> > Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> (v4) > Signed-off-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> > --- > drivers/gpu/drm/i915/i915_irq.c | 112 +++++++++++++++++++++++++++------------- > 1 file changed, 75 insertions(+), 37 deletions(-) > > diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c > index 0b471775ce38..653bab682d5e 100644 > --- a/drivers/gpu/drm/i915/i915_irq.c > +++ b/drivers/gpu/drm/i915/i915_irq.c > @@ -243,6 +243,41 @@ void i915_hotplug_interrupt_update(struct drm_i915_private *dev_priv, > spin_unlock_irq(&dev_priv->irq_lock); > } > > +static u32 > +gen11_gt_engine_identity(struct drm_i915_private * const i915, > + const unsigned int bank, const unsigned int bit); > + > +static bool gen11_reset_one_iir(struct drm_i915_private * const i915, > + const unsigned int bank, > + const unsigned int bit) > +{ > + void __iomem * const regs = i915->regs; > + u32 dw; > + > + lockdep_assert_held(&i915->irq_lock); > + > + dw = raw_reg_read(regs, GEN11_GT_INTR_DW(bank)); > + if (dw & BIT(bit)) { > + /* > + * According to the BSpec, DW_IIR bits cannot be cleared without > + * first servicing the Selector & Shared IIR registers. > + */ > + gen11_gt_engine_identity(i915, bank, bit); > + > + /* > + * We locked GT INT DW by reading it. If we want to (try > + * to) recover from this succesfully, we need to clear > + * our bit, otherwise we are locking the register for > + * everybody. > + */ > + raw_reg_write(regs, GEN11_GT_INTR_DW(bank), BIT(bit)); > + > + return true; > + } > + > + return false; > +} > + > /** > * ilk_update_display_irq - update DEIMR > * @dev_priv: driver private > @@ -412,26 +447,12 @@ static void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, u32 disable_m > /* though a barrier is missing here, but don't really need a one */ > } > > -static u32 > -gen11_gt_engine_identity(struct drm_i915_private * const i915, > - const unsigned int bank, const unsigned int bit); > - > void gen11_reset_rps_interrupts(struct drm_i915_private *dev_priv) > { > - u32 dw; > - > spin_lock_irq(&dev_priv->irq_lock); > > - /* > - * According to the BSpec, DW_IIR bits cannot be cleared without > - * first servicing the Selector & Shared IIR registers. > - */ > - dw = I915_READ_FW(GEN11_GT_INTR_DW0); > - while (dw & BIT(GEN11_GTPM)) { > - gen11_gt_engine_identity(dev_priv, 0, GEN11_GTPM); > - I915_WRITE_FW(GEN11_GT_INTR_DW0, BIT(GEN11_GTPM)); > - dw = I915_READ_FW(GEN11_GT_INTR_DW0); > - } > + while (gen11_reset_one_iir(dev_priv, 0, GEN11_GTPM)) > + ; > > dev_priv->gt_pm.rps.pm_iir = 0; > > @@ -455,10 +476,12 @@ void gen6_enable_rps_interrupts(struct drm_i915_private *dev_priv) > > spin_lock_irq(&dev_priv->irq_lock); > WARN_ON_ONCE(rps->pm_iir); > + > if (INTEL_GEN(dev_priv) >= 11) > - WARN_ON_ONCE(I915_READ_FW(GEN11_GT_INTR_DW0) & BIT(GEN11_GTPM)); > + WARN_ON_ONCE(gen11_reset_one_iir(dev_priv, 0, GEN11_GTPM)); > else > WARN_ON_ONCE(I915_READ(gen6_pm_iir(dev_priv)) & dev_priv->pm_rps_events); > + > rps->interrupts_enabled = true; > gen6_enable_pm_irq(dev_priv, dev_priv->pm_rps_events); > > @@ -2778,6 +2801,8 @@ gen11_gt_engine_identity(struct drm_i915_private * const i915, > u32 timeout_ts; > u32 ident; > > + lockdep_assert_held(&i915->irq_lock); > + > raw_reg_write(regs, GEN11_IIR_REG_SELECTOR(bank), BIT(bit)); > > /* > @@ -2856,36 +2881,49 @@ gen11_gt_identity_handler(struct drm_i915_private * const i915, > } > > static void > -gen11_gt_irq_handler(struct drm_i915_private * const i915, > - const u32 master_ctl) > +gen11_gt_bank_handler(struct drm_i915_private * const i915, > + const unsigned int bank) > { > void __iomem * const regs = i915->regs; > - unsigned int bank; > + unsigned long intr_dw; > + unsigned int bit; > > - for (bank = 0; bank < 2; bank++) { > - unsigned long intr_dw; > - unsigned int bit; > + lockdep_assert_held(&i915->irq_lock); > > - if (!(master_ctl & GEN11_GT_DW_IRQ(bank))) > - continue; > + intr_dw = raw_reg_read(regs, GEN11_GT_INTR_DW(bank)); > > - intr_dw = raw_reg_read(regs, GEN11_GT_INTR_DW(bank)); > + if (unlikely(!intr_dw)) { > + DRM_ERROR("GT_INTR_DW%u blank!\n", bank); > + return; > + } > > - if (unlikely(!intr_dw)) { > - DRM_ERROR("GT_INTR_DW%u blank!\n", bank); > - continue; > - } > + for_each_set_bit(bit, &intr_dw, 32) { > + const u32 ident = gen11_gt_engine_identity(i915, > + bank, bit); > + > + gen11_gt_identity_handler(i915, ident); > + } > > - for_each_set_bit(bit, &intr_dw, 32) { > - const u32 ident = gen11_gt_engine_identity(i915, > - bank, bit); > + /* Clear must be after shared has been served for engine */ > + raw_reg_write(regs, GEN11_GT_INTR_DW(bank), intr_dw); > +} > > - gen11_gt_identity_handler(i915, ident); > - } > +static void > +gen11_gt_irq_handler(struct drm_i915_private * const i915, > + const u32 master_ctl) > +{ > + unsigned int bank; > + > + spin_lock(&i915->irq_lock); > > - /* Clear must be after shared has been served for engine */ > - raw_reg_write(regs, GEN11_GT_INTR_DW(bank), intr_dw); > + for (bank = 0; bank < 2; bank++) { > + if (!(master_ctl & GEN11_GT_DW_IRQ(bank))) > + continue; > + > + gen11_gt_bank_handler(i915, bank); Since you refactored this to please sparse (thank you for that), I would also have changed the if() logic to call gen11_gt_bank_handler and omit continue, i.e.: + for (bank = 0; bank < 2; bank++) { + if (master_ctl & GEN11_GT_DW_IRQ(bank)) + gen11_gt_bank_handler(i915, bank); + } > + > + spin_unlock(&i915->irq_lock); > } > > static irqreturn_t gen11_irq_handler(int irq, void *arg) > But it does what is supposed to do so, Reviewed-by: Michel Thierry <michel.thierry@intel.com> BTW, now that we have gen11_reset_one_iir, we can 'correctly clear lost ctx-switch interrupts across reset for Gen11' and get rid of the TODO in clear_gtiir() ;) -Michel
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 0b471775ce38..653bab682d5e 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -243,6 +243,41 @@ void i915_hotplug_interrupt_update(struct drm_i915_private *dev_priv, spin_unlock_irq(&dev_priv->irq_lock); } +static u32 +gen11_gt_engine_identity(struct drm_i915_private * const i915, + const unsigned int bank, const unsigned int bit); + +static bool gen11_reset_one_iir(struct drm_i915_private * const i915, + const unsigned int bank, + const unsigned int bit) +{ + void __iomem * const regs = i915->regs; + u32 dw; + + lockdep_assert_held(&i915->irq_lock); + + dw = raw_reg_read(regs, GEN11_GT_INTR_DW(bank)); + if (dw & BIT(bit)) { + /* + * According to the BSpec, DW_IIR bits cannot be cleared without + * first servicing the Selector & Shared IIR registers. + */ + gen11_gt_engine_identity(i915, bank, bit); + + /* + * We locked GT INT DW by reading it. If we want to (try + * to) recover from this succesfully, we need to clear + * our bit, otherwise we are locking the register for + * everybody. + */ + raw_reg_write(regs, GEN11_GT_INTR_DW(bank), BIT(bit)); + + return true; + } + + return false; +} + /** * ilk_update_display_irq - update DEIMR * @dev_priv: driver private @@ -412,26 +447,12 @@ static void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, u32 disable_m /* though a barrier is missing here, but don't really need a one */ } -static u32 -gen11_gt_engine_identity(struct drm_i915_private * const i915, - const unsigned int bank, const unsigned int bit); - void gen11_reset_rps_interrupts(struct drm_i915_private *dev_priv) { - u32 dw; - spin_lock_irq(&dev_priv->irq_lock); - /* - * According to the BSpec, DW_IIR bits cannot be cleared without - * first servicing the Selector & Shared IIR registers. - */ - dw = I915_READ_FW(GEN11_GT_INTR_DW0); - while (dw & BIT(GEN11_GTPM)) { - gen11_gt_engine_identity(dev_priv, 0, GEN11_GTPM); - I915_WRITE_FW(GEN11_GT_INTR_DW0, BIT(GEN11_GTPM)); - dw = I915_READ_FW(GEN11_GT_INTR_DW0); - } + while (gen11_reset_one_iir(dev_priv, 0, GEN11_GTPM)) + ; dev_priv->gt_pm.rps.pm_iir = 0; @@ -455,10 +476,12 @@ void gen6_enable_rps_interrupts(struct drm_i915_private *dev_priv) spin_lock_irq(&dev_priv->irq_lock); WARN_ON_ONCE(rps->pm_iir); + if (INTEL_GEN(dev_priv) >= 11) - WARN_ON_ONCE(I915_READ_FW(GEN11_GT_INTR_DW0) & BIT(GEN11_GTPM)); + WARN_ON_ONCE(gen11_reset_one_iir(dev_priv, 0, GEN11_GTPM)); else WARN_ON_ONCE(I915_READ(gen6_pm_iir(dev_priv)) & dev_priv->pm_rps_events); + rps->interrupts_enabled = true; gen6_enable_pm_irq(dev_priv, dev_priv->pm_rps_events); @@ -2778,6 +2801,8 @@ gen11_gt_engine_identity(struct drm_i915_private * const i915, u32 timeout_ts; u32 ident; + lockdep_assert_held(&i915->irq_lock); + raw_reg_write(regs, GEN11_IIR_REG_SELECTOR(bank), BIT(bit)); /* @@ -2856,36 +2881,49 @@ gen11_gt_identity_handler(struct drm_i915_private * const i915, } static void -gen11_gt_irq_handler(struct drm_i915_private * const i915, - const u32 master_ctl) +gen11_gt_bank_handler(struct drm_i915_private * const i915, + const unsigned int bank) { void __iomem * const regs = i915->regs; - unsigned int bank; + unsigned long intr_dw; + unsigned int bit; - for (bank = 0; bank < 2; bank++) { - unsigned long intr_dw; - unsigned int bit; + lockdep_assert_held(&i915->irq_lock); - if (!(master_ctl & GEN11_GT_DW_IRQ(bank))) - continue; + intr_dw = raw_reg_read(regs, GEN11_GT_INTR_DW(bank)); - intr_dw = raw_reg_read(regs, GEN11_GT_INTR_DW(bank)); + if (unlikely(!intr_dw)) { + DRM_ERROR("GT_INTR_DW%u blank!\n", bank); + return; + } - if (unlikely(!intr_dw)) { - DRM_ERROR("GT_INTR_DW%u blank!\n", bank); - continue; - } + for_each_set_bit(bit, &intr_dw, 32) { + const u32 ident = gen11_gt_engine_identity(i915, + bank, bit); + + gen11_gt_identity_handler(i915, ident); + } - for_each_set_bit(bit, &intr_dw, 32) { - const u32 ident = gen11_gt_engine_identity(i915, - bank, bit); + /* Clear must be after shared has been served for engine */ + raw_reg_write(regs, GEN11_GT_INTR_DW(bank), intr_dw); +} - gen11_gt_identity_handler(i915, ident); - } +static void +gen11_gt_irq_handler(struct drm_i915_private * const i915, + const u32 master_ctl) +{ + unsigned int bank; + + spin_lock(&i915->irq_lock); - /* Clear must be after shared has been served for engine */ - raw_reg_write(regs, GEN11_GT_INTR_DW(bank), intr_dw); + for (bank = 0; bank < 2; bank++) { + if (!(master_ctl & GEN11_GT_DW_IRQ(bank))) + continue; + + gen11_gt_bank_handler(i915, bank); } + + spin_unlock(&i915->irq_lock); } static irqreturn_t gen11_irq_handler(int irq, void *arg)