Re: [Intel-gfx] [PATCH 05/19] drm/i915/icl: Interrupt handling
+ +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 = readl(regs + + i915_mmio_reg_offset(GEN11_GT_INTR_DW(bank))); + I think we should keep some kind of polling here, because there is going to be some delay between writing the selector and getting the correct value in the identity register and the CPU might also be running at a higher frequency than the GPU. Spec does not specify a time but implies that we have to wait for the valid bit to be set. + if (unlikely(!intr_dw)) + DRM_ERROR("GT_INTR_DW%u blank!\n", bank); + + 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); The identity register contains the class (bits 16-18) and instance (bits 20-25), so we can potentially decode them and call directly: gen11_cs_irq_handler(i915->engine_class[class][instance], iir); instead of having a big switch. The only problem with that would be that GuC and PM interrupts come out as class 4 instances 0 and 1, so once we add support for those we'd have to do something like if (class != OTHER_CLASS) gen11_cs_irq_handler(...); else { switch (instance) { case 0: gen11_guc_irq_handler(...); break; case 1: gen11_rps_irq_handler(...); break; default: MISSING_CASE(); } } not sure if decoding class and instance and having a small switch wins in the end against the big switch, so I won't complain whichever you pick ;) Daniele + } + + /* Clear must be after shared has been served for engine */ + writel(intr_dw, + regs + i915_mmio_reg_offset(GEN11_GT_INTR_DW(bank))); + } +} + ___ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Re: [Intel-gfx] [PATCH 05/19] drm/i915/icl: Interrupt handling
On 15/02/2018 16:27, Mika Kuoppala wrote: From: Tvrtko Ursulin I think a point has arrived when I almost don't recognize the code any longer so would want to relinquish the authorship if you don't mind. Regards, Tvrtko 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) Cc: Tvrtko Ursulin Cc: Daniele Ceraolo Spurio Cc: Chris Wilson Cc: Oscar Mateo Signed-off-by: Tvrtko Ursulin Signed-off-by: Rodrigo Vivi Signed-off-by: Daniele Ceraolo Spurio Signed-off-by: Oscar Mateo Signed-off-by: Paulo Zanoni Signed-off-by: Mika Kuoppala --- drivers/gpu/drm/i915/i915_irq.c | 222 drivers/gpu/drm/i915/intel_pm.c | 7 +- 2 files changed, 228 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b886bd459acc..e3914d1e204e 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; @@ -2746,6 +2752,143 @@ 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 ident; + + writel(BIT(bit), + regs + i915_mmio_reg_offset(GEN11_IIR_REG_SELECTOR(bank))); + + ident = readl(regs + + i915_mmio_reg_offset(GEN11_INTR_IDENTITY_REG(bank))); + + if (unlikely(!(ident & GEN11_INTR_DATA_VALID))) { + DRM_ERROR("INTR_IDENTITY_REG%u:%u 0x%08x not valid!\n", + bank, bit, ident); + return 0; +
[Intel-gfx] [PATCH 05/19] drm/i915/icl: Interrupt handling
From: Tvrtko Ursulin 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) Cc: Tvrtko Ursulin Cc: Daniele Ceraolo Spurio Cc: Chris Wilson Cc: Oscar Mateo Signed-off-by: Tvrtko Ursulin Signed-off-by: Rodrigo Vivi Signed-off-by: Daniele Ceraolo Spurio Signed-off-by: Oscar Mateo Signed-off-by: Paulo Zanoni Signed-off-by: Mika Kuoppala --- drivers/gpu/drm/i915/i915_irq.c | 222 drivers/gpu/drm/i915/intel_pm.c | 7 +- 2 files changed, 228 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b886bd459acc..e3914d1e204e 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; @@ -2746,6 +2752,143 @@ 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 ident; + + writel(BIT(bit), + regs + i915_mmio_reg_offset(GEN11_IIR_REG_SELECTOR(bank))); + + ident = readl(regs + + i915_mmio_reg_offset(GEN11_INTR_IDENTITY_REG(bank))); + + if (unlikely(!(ident & GEN11_INTR_DATA_VALID))) { + DRM_ERROR("INTR_IDENTITY_REG%u:%u 0x%08x not valid!\n", + bank, bit, ident); + return 0; + } + + writel(GEN11_INTR_DATA_VALID, + regs + i915_mmio_reg_offset(GEN11_INTR_IDENTITY_REG(bank))); + + return ident & GEN11_INTR_ENGINE_MASK; +} + +static void +gen11_gt_irq_handler(struct drm_i915_private *
Re: [Intel-gfx] [PATCH 05/19] drm/i915/icl: Interrupt handling
Chris Wilson writes: > Quoting Mika Kuoppala (2018-02-14 14:12:13) >> From: Tvrtko Ursulin >> >> 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) >> >> Cc: Tvrtko Ursulin >> Cc: Daniele Ceraolo Spurio >> Cc: Chris Wilson >> Cc: Oscar Mateo >> Signed-off-by: Tvrtko Ursulin >> Signed-off-by: Rodrigo Vivi >> Signed-off-by: Daniele Ceraolo Spurio >> Signed-off-by: Oscar Mateo >> Signed-off-by: Paulo Zanoni >> Signed-off-by: Mika Kuoppala >> --- >> drivers/gpu/drm/i915/i915_irq.c | 212 >> >> drivers/gpu/drm/i915/intel_pm.c | 7 +- >> 2 files changed, 218 insertions(+), 1 deletion(-) >> >> diff --git a/drivers/gpu/drm/i915/i915_irq.c >> b/drivers/gpu/drm/i915/i915_irq.c >> index b886bd459acc..9a2d12c8c44c 100644 >> --- a/drivers/gpu/drm/i915/i915_irq.c >> +++ b/drivers/gpu/drm/i915/i915_irq.c >> @@ -408,6 +408,37 @@ void gen6_reset_rps_interrupts(struct drm_i915_private >> *dev_priv) >> spin_unlock_irq(&dev_priv->irq_lock); >> } >> >> +static int gen11_service_shared_iir(struct drm_i915_private *dev_priv, >> + const unsigned int bank, >> + const unsigned int bit) >> +{ >> + u64 wait_end; >> + u32 ident; >> + int irq; >> + >> + I915_WRITE_FW(GEN11_IIR_REG_SELECTOR(bank), BIT(bit)); >> + /* >> +* NB: Specs do not specify how long to spin wait. >> +* Taking 100us as an educated guess >> +*/ >> + wait_end = (local_clock() >> 10) + 100; >> + do { >> + ident = I915_READ_FW(GEN11_INTR_IDENTITY_REG(bank)); >> + } while (!(ident & GEN11_INTR_DATA_VALID) && >> +!time_after32(local_clock() >> 10, wait_end)); > > Now you are just mixing types willy nilly :) > > No need for wait_end to be 64b when we are looking at a 100 interval. I threw the poll away. We can add it later if someone objects and/or evidence indicates that it is needed. But polling for 100us just in case in irq handler should not be the first step. > >> + >> + if (!(ident & GEN11_INTR_DATA_VALID)) { >> + DRM_ERROR("INTR_IDENTITY_REG%u:%u timed out!\n", bank, bit); >> + return -ETIMEDOUT; >> + } >> + >> + irq = ident & GEN11_INTR_ENGINE_MASK; >> + >> + I915_WRITE_FW(GEN11_INTR_IDENTITY_REG(bank), ident); Bspec tells that valid bit write should be enough here. >> + >> + return irq; > > return ident & GEN11_INTR_ENGINE_MASK; > > no need for irq, and why int return type? I made it return zero on unvalid. > > Why is this gen11 specific helper so far away from the irq_handler? Due to later patch in this series needing it, rc6 enabling due to rps reset. I moved those closer in both patches. > >> +static __always_inline void >> +gen11_cs_irq_handler(struct intel_engine_cs *engine, u32 iir) >> +{ >> + gen8_cs_irq_handler(engine, iir, 0); >> +} >> + >> +static void >> +gen11_gt_irq_handler(struct drm_i915_private *dev_priv, const u32 >> master_ctl) >> +{ >> + u16 irq[2][32]; >> + unsigned int bank, engine; >> + >> + memset(irq, 0, sizeof(irq)); >> + >> + for (bank = 0; bank < 2; bank++) { >> + unsigned long tmp; >> + unsigned int bit; >> + u32 dw; >> + int ret; >> + >> + if (!(master_ctl & GEN11_GT_DW_IRQ(bank))) >> + continue; >> + >> + dw = I915_READ_FW(GEN11_GT_INTR_DW(bank)); >> + if (!dw) >> + DRM_ERROR("GT_INTR_DW%u blank!\n", bank); >> + >> + tmp = dw; >> + for_each_set_bit(bit, &tmp, 32) { > > tmp is not required here. reading directly now to unsigned long dw_intr. > >> + ret = gen11_service_shared_iir(dev_priv, bank, bit); >> + if (unlikely(ret < 0)) >> + continue; >> + >> + irq[bank][bit] = ret; >> + } >> + >> + I915_WRITE_FW(GEN11_
Re: [Intel-gfx] [PATCH 05/19] drm/i915/icl: Interrupt handling
Quoting Mika Kuoppala (2018-02-14 14:12:13) > From: Tvrtko Ursulin > > 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) > > Cc: Tvrtko Ursulin > Cc: Daniele Ceraolo Spurio > Cc: Chris Wilson > Cc: Oscar Mateo > Signed-off-by: Tvrtko Ursulin > Signed-off-by: Rodrigo Vivi > Signed-off-by: Daniele Ceraolo Spurio > Signed-off-by: Oscar Mateo > Signed-off-by: Paulo Zanoni > Signed-off-by: Mika Kuoppala > --- > drivers/gpu/drm/i915/i915_irq.c | 212 > > drivers/gpu/drm/i915/intel_pm.c | 7 +- > 2 files changed, 218 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c > index b886bd459acc..9a2d12c8c44c 100644 > --- a/drivers/gpu/drm/i915/i915_irq.c > +++ b/drivers/gpu/drm/i915/i915_irq.c > @@ -408,6 +408,37 @@ void gen6_reset_rps_interrupts(struct drm_i915_private > *dev_priv) > spin_unlock_irq(&dev_priv->irq_lock); > } > > +static int gen11_service_shared_iir(struct drm_i915_private *dev_priv, > + const unsigned int bank, > + const unsigned int bit) > +{ > + u64 wait_end; > + u32 ident; > + int irq; > + > + I915_WRITE_FW(GEN11_IIR_REG_SELECTOR(bank), BIT(bit)); > + /* > +* NB: Specs do not specify how long to spin wait. > +* Taking 100us as an educated guess > +*/ > + wait_end = (local_clock() >> 10) + 100; > + do { > + ident = I915_READ_FW(GEN11_INTR_IDENTITY_REG(bank)); > + } while (!(ident & GEN11_INTR_DATA_VALID) && > +!time_after32(local_clock() >> 10, wait_end)); Now you are just mixing types willy nilly :) No need for wait_end to be 64b when we are looking at a 100 interval. > + > + if (!(ident & GEN11_INTR_DATA_VALID)) { > + DRM_ERROR("INTR_IDENTITY_REG%u:%u timed out!\n", bank, bit); > + return -ETIMEDOUT; > + } > + > + irq = ident & GEN11_INTR_ENGINE_MASK; > + > + I915_WRITE_FW(GEN11_INTR_IDENTITY_REG(bank), ident); > + > + return irq; return ident & GEN11_INTR_ENGINE_MASK; no need for irq, and why int return type? Why is this gen11 specific helper so far away from the irq_handler? > +static __always_inline void > +gen11_cs_irq_handler(struct intel_engine_cs *engine, u32 iir) > +{ > + gen8_cs_irq_handler(engine, iir, 0); > +} > + > +static void > +gen11_gt_irq_handler(struct drm_i915_private *dev_priv, const u32 master_ctl) > +{ > + u16 irq[2][32]; > + unsigned int bank, engine; > + > + memset(irq, 0, sizeof(irq)); > + > + for (bank = 0; bank < 2; bank++) { > + unsigned long tmp; > + unsigned int bit; > + u32 dw; > + int ret; > + > + if (!(master_ctl & GEN11_GT_DW_IRQ(bank))) > + continue; > + > + dw = I915_READ_FW(GEN11_GT_INTR_DW(bank)); > + if (!dw) > + DRM_ERROR("GT_INTR_DW%u blank!\n", bank); > + > + tmp = dw; > + for_each_set_bit(bit, &tmp, 32) { tmp is not required here. > + ret = gen11_service_shared_iir(dev_priv, bank, bit); > + if (unlikely(ret < 0)) > + continue; > + > + irq[bank][bit] = ret; > + } > + > + I915_WRITE_FW(GEN11_GT_INTR_DW(bank), dw); If we process the banks here, we won't need to memset 128 bytes and scan untouched cachelines! > + } > + > + if (irq[0][GEN11_RCS0]) > + gen11_cs_irq_handler(dev_priv->engine[RCS], > +irq[0][GEN11_RCS0]); > + > + if (irq[0][GEN11_BCS]) > + gen11_cs_irq_handler(dev_priv->engine[BCS], > +irq[0][GEN11_BCS]); > + > + for (engine = 0; engine < I915_MAX_VCS; engine++) > + if (irq[1][GEN11_VCS(engine)]) > + gen11_cs_irq_handler(dev_priv->e
[Intel-gfx] [PATCH 05/19] drm/i915/icl: Interrupt handling
From: Tvrtko Ursulin 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) Cc: Tvrtko Ursulin Cc: Daniele Ceraolo Spurio Cc: Chris Wilson Cc: Oscar Mateo Signed-off-by: Tvrtko Ursulin Signed-off-by: Rodrigo Vivi Signed-off-by: Daniele Ceraolo Spurio Signed-off-by: Oscar Mateo Signed-off-by: Paulo Zanoni Signed-off-by: Mika Kuoppala --- drivers/gpu/drm/i915/i915_irq.c | 212 drivers/gpu/drm/i915/intel_pm.c | 7 +- 2 files changed, 218 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b886bd459acc..9a2d12c8c44c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -408,6 +408,37 @@ void gen6_reset_rps_interrupts(struct drm_i915_private *dev_priv) spin_unlock_irq(&dev_priv->irq_lock); } +static int gen11_service_shared_iir(struct drm_i915_private *dev_priv, + const unsigned int bank, + const unsigned int bit) +{ + u64 wait_end; + u32 ident; + int irq; + + I915_WRITE_FW(GEN11_IIR_REG_SELECTOR(bank), BIT(bit)); + /* +* NB: Specs do not specify how long to spin wait. +* Taking 100us as an educated guess +*/ + wait_end = (local_clock() >> 10) + 100; + do { + ident = I915_READ_FW(GEN11_INTR_IDENTITY_REG(bank)); + } while (!(ident & GEN11_INTR_DATA_VALID) && +!time_after32(local_clock() >> 10, wait_end)); + + if (!(ident & GEN11_INTR_DATA_VALID)) { + DRM_ERROR("INTR_IDENTITY_REG%u:%u timed out!\n", bank, bit); + return -ETIMEDOUT; + } + + irq = ident & GEN11_INTR_ENGINE_MASK; + + I915_WRITE_FW(GEN11_INTR_IDENTITY_REG(bank), ident); + + return irq; +} + void gen6_enable_rps_interrupts(struct drm_i915_private *dev_priv) { struct intel_rps *rps = &dev_priv->gt_pm.rps; @@ -415,6 +446,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 +465,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; @@ -2746,6 +2783,102 @@ 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 *engine, u32 iir) +{ + gen8_cs_irq_handler(engine, iir, 0); +} + +static void +gen11_gt_irq_handler(struct drm_i915_private *dev_priv, const u32 master_ctl) +{ + u16 irq[2][32]; + unsigned int bank, engine; + + memset(irq, 0, sizeof(irq)); + + for (bank = 0; bank < 2; bank++) { + unsigned long tmp; + unsigned int bit; + u32 dw; + int ret; + + if (!(master_ctl & GEN11_GT_DW_IRQ(bank))) + continue; + + dw = I915_READ_FW(GEN11_GT_INTR_DW(bank)); + if (!dw) + DRM_ERROR("GT_INTR_DW%u blank!\n", bank); + + tmp = dw; + for_each_set_bit(bit, &tmp, 32) { + ret = gen11_service_shared_iir(dev_priv, bank, bit); + if (unlikely(ret < 0)) + continue; + + irq[bank][bit] = ret; + } + + I915_WRITE_FW(GEN11_GT_INTR_DW(bank), dw); + } + + if (irq[0][GEN11_RCS0]) + gen11_cs_irq_handler(dev_priv->engine[RCS], +irq[0][GEN11_RCS0]);