[Intel-gfx] [PATCH 4/4] drm/i915/icl: Interrupt handling

Mika Kuoppala mika.kuoppala at linux.intel.com
Thu Mar 1 12:22:32 UTC 2018


Paulo Zanoni <paulo.r.zanoni at intel.com> writes:

> Em Ter, 2018-02-27 às 11:51 -0800, Daniele Ceraolo Spurio escreveu:
>> 
>> On 20/02/18 07:37, Mika Kuoppala wrote:
>> > v2: Rebase.
>> > 
>> > v3:
>> >    * Remove DPF, it has been removed from SKL+.
>> >    * Fix -internal rebase wrt. execlists interrupt handling.
>> > 
>> > v4: Rebase.
>> > 
>> > v5:
>> >    * Updated for POR changes. (Daniele Ceraolo Spurio)
>> >    * Merged with irq handling fixes by Daniele Ceraolo Spurio:
>> >        * Simplify the code by using gen8_cs_irq_handler.
>> >        * Fix interrupt handling for the upstream kernel.
>> > 
>> > v6:
>> >    * Remove early bringup debug messages (Tvrtko)
>> >    * Add NB about arbitrary spin wait timeout (Tvrtko)
>> > 
>> > v7 (from Paulo):
>> >    * Don't try to write RO bits to registers.
>> >    * Don't check for PCH types that don't exist. PCH interrupts are
>> > not
>> >      here yet.
>> > 
>> > v9:
>> >    * squashed in selector and shared register handling (Daniele)
>> >    * skip writing of irq if data is not valid (Daniele)
>> >    * use time_after32 (Chris)
>> >    * use I915_MAX_VCS and I915_MAX_VECS (Daniele)
>> >    * remove fake pm interrupt handling for later patch (Mika)
>> > 
>> > v10:
>> >    * Direct processing of banks. clear banks early (Chris)
>> >    * remove poll on valid bit, only clear valid bit (Mika)
>> >    * use raw accessors, better naming (Chris)
>> > 
>> > v11:
>> >    * adapt to raw_reg_[read|write]
>> >    * bring back polling the valid bit (Daniele)
>> > 
>> > Cc: Tvrtko Ursulin <tvrtko.ursulin at intel.com>
>> > Cc: Daniele Ceraolo Spurio <daniele.ceraolospurio at intel.com>
>> > Cc: Chris Wilson <chris at chris-wilson.co.uk>
>> > Cc: Oscar Mateo <oscar.mateo at intel.com>
>> > Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin at intel.com>
>> > Signed-off-by: Rodrigo Vivi <rodrigo.vivi at intel.com>
>> > Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio at intel.
>> > com>
>> > Signed-off-by: Oscar Mateo <oscar.mateo at intel.com>
>> > Signed-off-by: Paulo Zanoni <paulo.r.zanoni at intel.com>
>> > Signed-off-by: Mika Kuoppala <mika.kuoppala at linux.intel.com>
>> > ---
>> >   drivers/gpu/drm/i915/i915_irq.c | 229
>> > ++++++++++++++++++++++++++++++++++++++++
>> >   drivers/gpu/drm/i915/intel_pm.c |   7 +-
>> >   2 files changed, 235 insertions(+), 1 deletion(-)
>> > 
>> > diff --git a/drivers/gpu/drm/i915/i915_irq.c
>> > b/drivers/gpu/drm/i915/i915_irq.c
>> > index 17de6cef2a30..a79f47ac742a 100644
>> > --- a/drivers/gpu/drm/i915/i915_irq.c
>> > +++ b/drivers/gpu/drm/i915/i915_irq.c
>> > @@ -415,6 +415,9 @@ void gen6_enable_rps_interrupts(struct
>> > drm_i915_private *dev_priv)
>> >   	if (READ_ONCE(rps->interrupts_enabled))
>> >   		return;
>> >   
>> > +	if (WARN_ON_ONCE(IS_GEN11(dev_priv)))
>> > +		return;
>> > +
>> >   	spin_lock_irq(&dev_priv->irq_lock);
>> >   	WARN_ON_ONCE(rps->pm_iir);
>> >   	WARN_ON_ONCE(I915_READ(gen6_pm_iir(dev_priv)) & dev_priv-
>> > >pm_rps_events);
>> > @@ -431,6 +434,9 @@ void gen6_disable_rps_interrupts(struct
>> > drm_i915_private *dev_priv)
>> >   	if (!READ_ONCE(rps->interrupts_enabled))
>> >   		return;
>> >   
>> > +	if (WARN_ON_ONCE(IS_GEN11(dev_priv)))
>> > +		return;
>> > +
>> >   	spin_lock_irq(&dev_priv->irq_lock);
>> >   	rps->interrupts_enabled = false;
>> >   
>> > @@ -2755,6 +2761,150 @@ static void __fini_wedge(struct wedge_me
>> > *w)
>> >   	     (W)->i915;						
>> > 	\
>> >   	     __fini_wedge((W)))
>> >   
>> > +static __always_inline void
>> > +gen11_cs_irq_handler(struct intel_engine_cs * const engine, const
>> > u32 iir)
>> > +{
>> > +	gen8_cs_irq_handler(engine, iir, 0);
>> > +}
>> > +
>> > +static void
>> > +gen11_gt_engine_irq_handler(struct drm_i915_private * const i915,
>> > +			    const unsigned int bank,
>> > +			    const unsigned int engine_n,
>> > +			    const u16 iir)
>> > +{
>> > +	struct intel_engine_cs ** const engine = i915->engine;
>> > +
>> > +	switch (bank) {
>> > +	case 0:
>> > +		switch (engine_n) {
>> > +
>> > +		case GEN11_RCS0:
>> > +			return gen11_cs_irq_handler(engine[RCS],
>> > iir);
>> > +
>> > +		case GEN11_BCS:
>> > +			return gen11_cs_irq_handler(engine[BCS],
>> > iir);
>> > +		}
>> > +	case 1:
>> > +		switch (engine_n) {
>> > +
>> > +		case GEN11_VCS(0):
>> > +			return
>> > gen11_cs_irq_handler(engine[_VCS(0)], iir);
>> > +		case GEN11_VCS(1):
>> > +			return
>> > gen11_cs_irq_handler(engine[_VCS(1)], iir);
>> > +		case GEN11_VCS(2):
>> > +			return
>> > gen11_cs_irq_handler(engine[_VCS(2)], iir);
>> > +		case GEN11_VCS(3):
>> > +			return
>> > gen11_cs_irq_handler(engine[_VCS(3)], iir);
>> > +
>> > +		case GEN11_VECS(0):
>> > +			return
>> > gen11_cs_irq_handler(engine[_VECS(0)], iir);
>> > +		case GEN11_VECS(1):
>> > +			return
>> > gen11_cs_irq_handler(engine[_VECS(1)], iir);
>> > +		}
>> > +	}
>> > +}
>> > +
>> > +static u32
>> > +gen11_gt_engine_intr(struct drm_i915_private * const i915,
>> > +		     const unsigned int bank, const unsigned int
>> > bit)
>> > +{
>> > +	void __iomem * const regs = i915->regs;
>> > +	u32 timeout_ts;
>> > +	u32 ident;
>> > +
>> > +	raw_reg_write(regs, GEN11_IIR_REG_SELECTOR(bank),
>> > BIT(bit));
>> > +
>> > +	/*
>> > +	 * NB: Specs do not specify how long to spin wait,
>> > +	 * so we do ~100us as an educated guess.
>> > +	 */
>> > +	timeout_ts = (local_clock() >> 10) + 100;
>> > +	do {
>> > +		ident = raw_reg_read(regs,
>> > GEN11_INTR_IDENTITY_REG(bank));
>> > +	} while (!(ident & GEN11_INTR_DATA_VALID) &&
>> > +		 !time_after32(local_clock() >> 10, timeout_ts));
>> > +
>> > +	if (unlikely(!(ident & GEN11_INTR_DATA_VALID))) {
>> > +		DRM_ERROR("INTR_IDENTITY_REG%u:%u 0x%08x not
>> > valid!\n",
>> > +			  bank, bit, ident);
>> > +		return 0;
>> > +	}
>> > +
>> > +	raw_reg_write(regs, GEN11_INTR_IDENTITY_REG(bank),
>> > +		      GEN11_INTR_DATA_VALID);
>> > +
>> > +	return ident & GEN11_INTR_ENGINE_MASK;
>> > +}
>> > +
>> > +static void
>> > +gen11_gt_irq_handler(struct drm_i915_private * const i915,
>> > +		     const u32 master_ctl)
>> > +{
>> > +	void __iomem * const regs = i915->regs;
>> > +	unsigned int bank;
>> > +
>> > +	for (bank = 0; bank < 2; bank++) {
>> > +		unsigned long intr_dw;
>> > +		unsigned int bit;
>> > +
>> > +		if (!(master_ctl & GEN11_GT_DW_IRQ(bank)))
>> > +			continue;
>> > +
>> > +		intr_dw = raw_reg_read(regs,
>> > GEN11_GT_INTR_DW(bank));
>> > +
>> > +		if (unlikely(!intr_dw))
>> > +			DRM_ERROR("GT_INTR_DW%u blank!\n", bank);
>> 
>> Could continue here, since the other operations in the loop won't be 
>> meaningful if intr_dw=0
>> 
>> > +
>> > +		for_each_set_bit(bit, &intr_dw, 32) {
>> > +			const u16 iir = gen11_gt_engine_intr(i915,
>> > bank, bit);
>> > +
>> > +			if (unlikely(!iir))
>> > +				continue;
>> > +
>> > +			gen11_gt_engine_irq_handler(i915, bank,
>> > bit, iir);
>> > +		}
>> > +
>> > +		/* Clear must be after shared has been served for
>> > engine */
>> > +		raw_reg_write(regs, GEN11_GT_INTR_DW(bank),
>> > intr_dw);
>> > +	}
>> > +}
>> > +
>> > +static irqreturn_t gen11_irq_handler(int irq, void *arg)
>> > +{
>> > +	struct drm_i915_private * const i915 = to_i915(arg);
>> > +	void __iomem * const regs = i915->regs;
>> > +	u32 master_ctl;
>> > +
>> > +	if (!intel_irqs_enabled(i915))
>> > +		return IRQ_NONE;
>> > +
>> > +	master_ctl = raw_reg_read(regs, GEN11_GFX_MSTR_IRQ);
>> > +	master_ctl &= ~GEN11_MASTER_IRQ;
>> > +	if (!master_ctl)
>> > +		return IRQ_NONE;
>> > +
>> > +	/* Disable interrupts. */
>> > +	raw_reg_write(regs, GEN11_GFX_MSTR_IRQ, 0);
>> > +
>> > +	/* Find, clear, then process each source of interrupt. */
>> > +	gen11_gt_irq_handler(i915, master_ctl);
>> > +
>> > +	/* IRQs are synced during runtime_suspend, we don't
>> > require a wakeref */
>> > +	if (master_ctl & GEN11_DISPLAY_IRQ) {
>> > +		const u32 disp_ctl = raw_reg_read(regs,
>> > GEN11_DISPLAY_INT_CTL);
>> > +
>> > +		disable_rpm_wakeref_asserts(i915);
>> > +		gen8_de_irq_handler(i915, disp_ctl);
>> 
>> gen8_de_irq_handler refers to the provided value as "master_ctl". 
>> GEN11_DISPLAY_INT_CTL has the same format as GEN8_MASTER_IRQ for the 
>> display-related bits (16-30) so it is ok to provide disp_ctl, but we 
>> could use a comment to explain that. Also, gen8_de_irq_handler logs 
>> errors blaming the master when things go wrong, so we could update
>> that 
>> to make things clearer, but that can come as a follow up.
>> 
>> I've checked the bit definitions of the registers used in 
>> gen8_de_irq_handler and some of the bits have moved, but AFAICS
>> among 
>> the ones we use the only one that is impacted is GEN8_DE_MISC_GSE,
>> which 
>> is now gone (bit is now reserved). This shouldn't impact 
>> gen8_de_irq_handler because the interrupt shouldn't trigger at all,
>> but 
>> we could avoid enabling it from gen8_de_irq_postinstall.
>
> We have a patch for the GSE bit. Also, a few other display-related
> interrupts have changed, and we have patches for them too.
>
> All the display-related interrupt patches depend on this patch here, I
> didn't send them yet to the list since I realized this patch here would
> still get a few new versions, generating more and conflicts on each
> version.
>
> Once this one is merged we can send the display interrupt ones.
>

This is now pushed with the suggested changes by Daniele.
Thanks for review.
-Mika


More information about the Intel-gfx mailing list