[Intel-gfx] [PATCH 23/36] drm/i915: Move all the RPS irq handlers to intel_gt_pm

Sagar Arun Kamble sagar.a.kamble at intel.com
Fri Mar 16 07:43:58 UTC 2018


As per discussion with Michal w.r.t moving GuC interrupt handling 
functions to intel_guc|_interrupt.c, I agreed that
since most functions (gen9_*_guc_interrupts) are touching dev_priv level 
interrupt registers we should keep themĀ  in i915_irq.c
Handler for rps can be created and be in gt_pm.c like in this patch but 
gen*_*_rps|guc_interrupts need to be in i915_irq.c.

And if we want to move them below change is needed:
gen9_guc_irq_handler is left in i915_irq.c and gen9_*_guc_interrupts 
declarations are in i915_drv.h.

Thanks,
Sagar

On 3/14/2018 3:07 PM, Chris Wilson wrote:
> Since all the RPS handling code is in intel_gt_pm, move the irq handlers
> there as well so that it all contained within one file.
>
> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
> ---
>   drivers/gpu/drm/i915/i915_drv.h         |  10 +-
>   drivers/gpu/drm/i915/i915_irq.c         | 287 ++++----------------------------
>   drivers/gpu/drm/i915/intel_drv.h        |   5 -
>   drivers/gpu/drm/i915/intel_gt_pm.c      | 223 ++++++++++++++++++++++++-
>   drivers/gpu/drm/i915/intel_gt_pm.h      |   5 +
>   drivers/gpu/drm/i915/intel_ringbuffer.c |   1 +
>   6 files changed, 260 insertions(+), 271 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index a57b20f95cdc..7c9cb2f9188b 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -743,6 +743,9 @@ struct intel_rps {
>   	/* PM interrupt bits that should never be masked */
>   	u32 pm_intrmsk_mbz;
>   
> +	u32 pm_events;
> +	u32 guc_events;
> +
>   	/* Frequencies are stored in potentially platform dependent multiples.
>   	 * In other words, *_freq needs to be multiplied by X to be interesting.
>   	 * Soft limits are those which are used for the dynamic reclocking done
> @@ -793,6 +796,9 @@ struct intel_gen6_power_mgmt {
>   	struct intel_rps rps;
>   	struct intel_rc6 rc6;
>   	struct intel_llc_pstate llc_pstate;
> +
> +	u32 imr;
> +	u32 ier;
>   };
>   
>   /* defined intel_pm.c */
> @@ -1641,10 +1647,6 @@ struct drm_i915_private {
>   		u32 de_irq_mask[I915_MAX_PIPES];
>   	};
>   	u32 gt_irq_mask;
> -	u32 pm_imr;
> -	u32 pm_ier;
> -	u32 pm_rps_events;
> -	u32 pm_guc_events;
>   	u32 pipestat_irq_mask[I915_MAX_PIPES];
>   
>   	struct i915_hotplug hotplug;
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index d9cf4f81979e..dfb711ca4d27 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -33,9 +33,11 @@
>   #include <linux/circ_buf.h>
>   #include <drm/drmP.h>
>   #include <drm/i915_drm.h>
> +
>   #include "i915_drv.h"
>   #include "i915_trace.h"
>   #include "intel_drv.h"
> +#include "intel_gt_pm.h"
>   
>   /**
>    * DOC: interrupt handling
> @@ -202,7 +204,6 @@ static void gen2_assert_iir_is_zero(struct drm_i915_private *dev_priv,
>   	POSTING_READ16(type##IMR); \
>   } while (0)
>   
> -static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir);
>   static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir);
>   
>   /* For display hotplug interrupt */
> @@ -306,194 +307,6 @@ void gen5_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask)
>   	ilk_update_gt_irq(dev_priv, mask, 0);
>   }
>   
> -static i915_reg_t gen6_pm_iir(struct drm_i915_private *dev_priv)
> -{
> -	return INTEL_GEN(dev_priv) >= 8 ? GEN8_GT_IIR(2) : GEN6_PMIIR;
> -}
> -
> -static i915_reg_t gen6_pm_imr(struct drm_i915_private *dev_priv)
> -{
> -	return INTEL_GEN(dev_priv) >= 8 ? GEN8_GT_IMR(2) : GEN6_PMIMR;
> -}
> -
> -static i915_reg_t gen6_pm_ier(struct drm_i915_private *dev_priv)
> -{
> -	return INTEL_GEN(dev_priv) >= 8 ? GEN8_GT_IER(2) : GEN6_PMIER;
> -}
> -
> -/**
> - * snb_update_pm_irq - update GEN6_PMIMR
> - * @dev_priv: driver private
> - * @interrupt_mask: mask of interrupt bits to update
> - * @enabled_irq_mask: mask of interrupt bits to enable
> - */
> -static void snb_update_pm_irq(struct drm_i915_private *dev_priv,
> -			      uint32_t interrupt_mask,
> -			      uint32_t enabled_irq_mask)
> -{
> -	uint32_t new_val;
> -
> -	WARN_ON(enabled_irq_mask & ~interrupt_mask);
> -
> -	lockdep_assert_held(&dev_priv->irq_lock);
> -
> -	new_val = dev_priv->pm_imr;
> -	new_val &= ~interrupt_mask;
> -	new_val |= (~enabled_irq_mask & interrupt_mask);
> -
> -	if (new_val != dev_priv->pm_imr) {
> -		dev_priv->pm_imr = new_val;
> -		I915_WRITE(gen6_pm_imr(dev_priv), dev_priv->pm_imr);
> -		POSTING_READ(gen6_pm_imr(dev_priv));
> -	}
> -}
> -
> -void gen6_unmask_pm_irq(struct drm_i915_private *dev_priv, u32 mask)
> -{
> -	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
> -		return;
> -
> -	snb_update_pm_irq(dev_priv, mask, mask);
> -}
> -
> -static void __gen6_mask_pm_irq(struct drm_i915_private *dev_priv, u32 mask)
> -{
> -	snb_update_pm_irq(dev_priv, mask, 0);
> -}
> -
> -void gen6_mask_pm_irq(struct drm_i915_private *dev_priv, u32 mask)
> -{
> -	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
> -		return;
> -
> -	__gen6_mask_pm_irq(dev_priv, mask);
> -}
> -
> -static void gen6_reset_pm_iir(struct drm_i915_private *dev_priv, u32 reset_mask)
> -{
> -	i915_reg_t reg = gen6_pm_iir(dev_priv);
> -
> -	lockdep_assert_held(&dev_priv->irq_lock);
> -
> -	I915_WRITE(reg, reset_mask);
> -	I915_WRITE(reg, reset_mask);
> -	POSTING_READ(reg);
> -}
> -
> -static void gen6_enable_pm_irq(struct drm_i915_private *dev_priv, u32 enable_mask)
> -{
> -	lockdep_assert_held(&dev_priv->irq_lock);
> -
> -	dev_priv->pm_ier |= enable_mask;
> -	I915_WRITE(gen6_pm_ier(dev_priv), dev_priv->pm_ier);
> -	gen6_unmask_pm_irq(dev_priv, enable_mask);
> -	/* unmask_pm_irq provides an implicit barrier (POSTING_READ) */
> -}
> -
> -static void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, u32 disable_mask)
> -{
> -	lockdep_assert_held(&dev_priv->irq_lock);
> -
> -	dev_priv->pm_ier &= ~disable_mask;
> -	__gen6_mask_pm_irq(dev_priv, disable_mask);
> -	I915_WRITE(gen6_pm_ier(dev_priv), dev_priv->pm_ier);
> -	/* though a barrier is missing here, but don't really need a one */
> -}
> -
> -void gen6_reset_rps_interrupts(struct drm_i915_private *dev_priv)
> -{
> -	spin_lock_irq(&dev_priv->irq_lock);
> -	gen6_reset_pm_iir(dev_priv, dev_priv->pm_rps_events);
> -	dev_priv->gt_pm.rps.pm_iir = 0;
> -	spin_unlock_irq(&dev_priv->irq_lock);
> -}
> -
> -void gen6_enable_rps_interrupts(struct drm_i915_private *dev_priv)
> -{
> -	struct intel_rps *rps = &dev_priv->gt_pm.rps;
> -
> -	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);
> -	rps->interrupts_enabled = true;
> -	gen6_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
> -
> -	spin_unlock_irq(&dev_priv->irq_lock);
> -}
> -
> -void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv)
> -{
> -	struct intel_rps *rps = &dev_priv->gt_pm.rps;
> -
> -	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;
> -
> -	I915_WRITE(GEN6_PMINTRMSK, gen6_sanitize_rps_pm_mask(dev_priv, ~0u));
> -
> -	gen6_disable_pm_irq(dev_priv, dev_priv->pm_rps_events);
> -
> -	spin_unlock_irq(&dev_priv->irq_lock);
> -	synchronize_irq(dev_priv->drm.irq);
> -
> -	/* Now that we will not be generating any more work, flush any
> -	 * outstanding tasks. As we are called on the RPS idle path,
> -	 * we will reset the GPU to minimum frequencies, so the current
> -	 * state of the worker can be discarded.
> -	 */
> -	cancel_work_sync(&rps->work);
> -	gen6_reset_rps_interrupts(dev_priv);
> -}
> -
> -void gen9_reset_guc_interrupts(struct drm_i915_private *dev_priv)
> -{
> -	assert_rpm_wakelock_held(dev_priv);
> -
> -	spin_lock_irq(&dev_priv->irq_lock);
> -	gen6_reset_pm_iir(dev_priv, dev_priv->pm_guc_events);
> -	spin_unlock_irq(&dev_priv->irq_lock);
> -}
> -
> -void gen9_enable_guc_interrupts(struct drm_i915_private *dev_priv)
> -{
> -	assert_rpm_wakelock_held(dev_priv);
> -
> -	spin_lock_irq(&dev_priv->irq_lock);
> -	if (!dev_priv->guc.interrupts_enabled) {
> -		WARN_ON_ONCE(I915_READ(gen6_pm_iir(dev_priv)) &
> -				       dev_priv->pm_guc_events);
> -		dev_priv->guc.interrupts_enabled = true;
> -		gen6_enable_pm_irq(dev_priv, dev_priv->pm_guc_events);
> -	}
> -	spin_unlock_irq(&dev_priv->irq_lock);
> -}
> -
> -void gen9_disable_guc_interrupts(struct drm_i915_private *dev_priv)
> -{
> -	assert_rpm_wakelock_held(dev_priv);
> -
> -	spin_lock_irq(&dev_priv->irq_lock);
> -	dev_priv->guc.interrupts_enabled = false;
> -
> -	gen6_disable_pm_irq(dev_priv, dev_priv->pm_guc_events);
> -
> -	spin_unlock_irq(&dev_priv->irq_lock);
> -	synchronize_irq(dev_priv->drm.irq);
> -
> -	gen9_reset_guc_interrupts(dev_priv);
> -}
> -
>   /**
>    * bdw_update_port_irq - update DE port interrupt
>    * @dev_priv: driver private
> @@ -1308,11 +1121,11 @@ static void gen8_gt_irq_ack(struct drm_i915_private *i915,
>   
>   	if (master_ctl & (GEN8_GT_PM_IRQ | GEN8_GT_GUC_IRQ)) {
>   		gt_iir[2] = raw_reg_read(regs, GEN8_GT_IIR(2));
> -		if (likely(gt_iir[2] & (i915->pm_rps_events |
> -					i915->pm_guc_events)))
> +		if (likely(gt_iir[2] & (i915->gt_pm.rps.pm_events |
> +					i915->gt_pm.rps.guc_events)))
>   			raw_reg_write(regs, GEN8_GT_IIR(2),
> -				      gt_iir[2] & (i915->pm_rps_events |
> -						   i915->pm_guc_events));
> +				      gt_iir[2] & (i915->gt_pm.rps.pm_events |
> +						   i915->gt_pm.rps.guc_events));
>   	}
>   
>   	if (master_ctl & GEN8_GT_VECS_IRQ) {
> @@ -1345,7 +1158,7 @@ static void gen8_gt_irq_handler(struct drm_i915_private *i915,
>   	}
>   
>   	if (master_ctl & (GEN8_GT_PM_IRQ | GEN8_GT_GUC_IRQ)) {
> -		gen6_rps_irq_handler(i915, gt_iir[2]);
> +		intel_gt_pm_irq_handler(i915, gt_iir[2]);
>   		gen9_guc_irq_handler(i915, gt_iir[2]);
>   	}
>   }
> @@ -1596,35 +1409,6 @@ static void i9xx_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
>   				     res1, res2);
>   }
>   
> -/* The RPS events need forcewake, so we add them to a work queue and mask their
> - * IMR bits until the work is done. Other interrupts can be processed without
> - * the work queue. */
> -static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
> -{
> -	struct intel_rps *rps = &dev_priv->gt_pm.rps;
> -
> -	if (pm_iir & dev_priv->pm_rps_events) {
> -		spin_lock(&dev_priv->irq_lock);
> -		gen6_mask_pm_irq(dev_priv, pm_iir & dev_priv->pm_rps_events);
> -		if (rps->interrupts_enabled) {
> -			rps->pm_iir |= pm_iir & dev_priv->pm_rps_events;
> -			schedule_work(&rps->work);
> -		}
> -		spin_unlock(&dev_priv->irq_lock);
> -	}
> -
> -	if (INTEL_GEN(dev_priv) >= 8)
> -		return;
> -
> -	if (HAS_VEBOX(dev_priv)) {
> -		if (pm_iir & PM_VEBOX_USER_INTERRUPT)
> -			notify_ring(dev_priv->engine[VECS]);
> -
> -		if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT)
> -			DRM_DEBUG("Command parser error, pm_iir 0x%08x\n", pm_iir);
> -	}
> -}
> -
>   static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 gt_iir)
>   {
>   	if (gt_iir & GEN9_GUC_TO_HOST_INT_EVENT)
> @@ -1832,6 +1616,19 @@ static void i9xx_hpd_irq_handler(struct drm_i915_private *dev_priv,
>   	}
>   }
>   
> +static void gen6_pm_extra_irq_handler(struct drm_i915_private *dev_priv,
> +				      u32 pm_iir)
> +{
> +	if (HAS_VEBOX(dev_priv)) {
> +		if (pm_iir & PM_VEBOX_USER_INTERRUPT)
> +			notify_ring(dev_priv->engine[VECS]);
> +
> +		if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT)
> +			DRM_DEBUG("Command parser error, pm_iir 0x%08x\n",
> +				  pm_iir);
> +	}
> +}
> +
>   static irqreturn_t valleyview_irq_handler(int irq, void *arg)
>   {
>   	struct drm_device *dev = arg;
> @@ -1906,7 +1703,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
>   		if (gt_iir)
>   			snb_gt_irq_handler(dev_priv, gt_iir);
>   		if (pm_iir)
> -			gen6_rps_irq_handler(dev_priv, pm_iir);
> +			intel_gt_pm_irq_handler(dev_priv, pm_iir);
>   
>   		if (hotplug_status)
>   			i9xx_hpd_irq_handler(dev_priv, hotplug_status);
> @@ -2351,7 +2148,8 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
>   		if (pm_iir) {
>   			I915_WRITE(GEN6_PMIIR, pm_iir);
>   			ret = IRQ_HANDLED;
> -			gen6_rps_irq_handler(dev_priv, pm_iir);
> +			intel_gt_pm_irq_handler(dev_priv, pm_iir);
> +			gen6_pm_extra_irq_handler(dev_priv, pm_iir);
>   		}
>   	}
>   
> @@ -3496,11 +3294,11 @@ static void gen5_gt_irq_postinstall(struct drm_device *dev)
>   		 */
>   		if (HAS_VEBOX(dev_priv)) {
>   			pm_irqs |= PM_VEBOX_USER_INTERRUPT;
> -			dev_priv->pm_ier |= PM_VEBOX_USER_INTERRUPT;
> +			dev_priv->gt_pm.ier |= PM_VEBOX_USER_INTERRUPT;
>   		}
>   
> -		dev_priv->pm_imr = 0xffffffff;
> -		GEN3_IRQ_INIT(GEN6_PM, dev_priv->pm_imr, pm_irqs);
> +		dev_priv->gt_pm.imr = 0xffffffff;
> +		GEN3_IRQ_INIT(GEN6_PM, dev_priv->gt_pm.imr, pm_irqs);
>   	}
>   }
>   
> @@ -3616,15 +3414,15 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
>   	if (HAS_L3_DPF(dev_priv))
>   		gt_interrupts[0] |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
>   
> -	dev_priv->pm_ier = 0x0;
> -	dev_priv->pm_imr = ~dev_priv->pm_ier;
> +	dev_priv->gt_pm.ier = 0x0;
> +	dev_priv->gt_pm.imr = ~dev_priv->gt_pm.ier;
>   	GEN8_IRQ_INIT_NDX(GT, 0, ~gt_interrupts[0], gt_interrupts[0]);
>   	GEN8_IRQ_INIT_NDX(GT, 1, ~gt_interrupts[1], gt_interrupts[1]);
>   	/*
>   	 * RPS interrupts will get enabled/disabled on demand when RPS itself
>   	 * is enabled/disabled. Same wil be the case for GuC interrupts.
>   	 */
> -	GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->pm_imr, dev_priv->pm_ier);
> +	GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->gt_pm.imr, dev_priv->gt_pm.ier);
>   	GEN8_IRQ_INIT_NDX(GT, 3, ~gt_interrupts[3], gt_interrupts[3]);
>   }
>   
> @@ -3714,7 +3512,7 @@ static void gen11_gt_irq_postinstall(struct drm_i915_private *dev_priv)
>   	I915_WRITE(GEN11_VCS2_VCS3_INTR_MASK,	~(irqs | irqs << 16));
>   	I915_WRITE(GEN11_VECS0_VECS1_INTR_MASK,	~(irqs | irqs << 16));
>   
> -	dev_priv->pm_imr = 0xffffffff; /* TODO */
> +	dev_priv->gt_pm.imr = 0xffffffff; /* TODO */
>   }
>   
>   static int gen11_irq_postinstall(struct drm_device *dev)
> @@ -4095,7 +3893,6 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
>   void intel_irq_init(struct drm_i915_private *dev_priv)
>   {
>   	struct drm_device *dev = &dev_priv->drm;
> -	struct intel_rps *rps = &dev_priv->gt_pm.rps;
>   	int i;
>   
>   	intel_hpd_init_work(dev_priv);
> @@ -4104,30 +3901,6 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
>   	for (i = 0; i < MAX_L3_SLICES; ++i)
>   		dev_priv->l3_parity.remap_info[i] = NULL;
>   
> -	if (HAS_GUC_SCHED(dev_priv))
> -		dev_priv->pm_guc_events = GEN9_GUC_TO_HOST_INT_EVENT;
> -
> -	/* Let's track the enabled rps events */
> -	if (IS_VALLEYVIEW(dev_priv))
> -		/* WaGsvRC0ResidencyMethod:vlv */
> -		dev_priv->pm_rps_events = GEN6_PM_RP_UP_EI_EXPIRED;
> -	else
> -		dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS;
> -
> -	rps->pm_intrmsk_mbz = 0;
> -
> -	/*
> -	 * SNB,IVB,HSW can while VLV,CHV may hard hang on looping batchbuffer
> -	 * if GEN6_PM_UP_EI_EXPIRED is masked.
> -	 *
> -	 * TODO: verify if this can be reproduced on VLV,CHV.
> -	 */
> -	if (INTEL_GEN(dev_priv) <= 7)
> -		rps->pm_intrmsk_mbz |= GEN6_PM_RP_UP_EI_EXPIRED;
> -
> -	if (INTEL_GEN(dev_priv) >= 8)
> -		rps->pm_intrmsk_mbz |= GEN8_PMINTR_DISABLE_REDIRECT_TO_GUC;
> -
>   	if (IS_GEN2(dev_priv)) {
>   		/* Gen2 doesn't have a hardware frame counter */
>   		dev->max_vblank_count = 0;
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 60638e0be745..e684b2f2f575 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1323,11 +1323,6 @@ void intel_check_pch_fifo_underruns(struct drm_i915_private *dev_priv);
>   /* i915_irq.c */
>   void gen5_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
>   void gen5_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
> -void gen6_mask_pm_irq(struct drm_i915_private *dev_priv, u32 mask);
> -void gen6_unmask_pm_irq(struct drm_i915_private *dev_priv, u32 mask);
> -void gen6_reset_rps_interrupts(struct drm_i915_private *dev_priv);
> -void gen6_enable_rps_interrupts(struct drm_i915_private *dev_priv);
> -void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv);
>   
>   static inline u32 gen6_sanitize_rps_pm_mask(const struct drm_i915_private *i915,
>   					    u32 mask)
> diff --git a/drivers/gpu/drm/i915/intel_gt_pm.c b/drivers/gpu/drm/i915/intel_gt_pm.c
> index 293cea1221af..0cf13e786fe6 100644
> --- a/drivers/gpu/drm/i915/intel_gt_pm.c
> +++ b/drivers/gpu/drm/i915/intel_gt_pm.c
> @@ -314,7 +314,7 @@ static u32 gen6_rps_pm_mask(struct drm_i915_private *dev_priv, u8 val)
>   		mask |= (GEN6_PM_RP_UP_EI_EXPIRED |
>   			 GEN6_PM_RP_UP_THRESHOLD);
>   
> -	mask &= dev_priv->pm_rps_events;
> +	mask &= rps->pm_events;
>   
>   	return gen6_sanitize_rps_pm_mask(dev_priv, ~mask);
>   }
> @@ -442,6 +442,132 @@ static int intel_set_rps(struct drm_i915_private *dev_priv, u8 val)
>   	return err;
>   }
>   
> +static i915_reg_t gen6_pm_iir(struct drm_i915_private *dev_priv)
> +{
> +	return INTEL_GEN(dev_priv) >= 8 ? GEN8_GT_IIR(2) : GEN6_PMIIR;
> +}
> +
> +static i915_reg_t gen6_pm_ier(struct drm_i915_private *dev_priv)
> +{
> +	return INTEL_GEN(dev_priv) >= 8 ? GEN8_GT_IER(2) : GEN6_PMIER;
> +}
> +
> +static i915_reg_t gen6_pm_imr(struct drm_i915_private *dev_priv)
> +{
> +	return INTEL_GEN(dev_priv) >= 8 ? GEN8_GT_IMR(2) : GEN6_PMIMR;
> +}
> +
> +static void gen6_update_pm_irq(struct drm_i915_private *dev_priv,
> +			       u32 interrupt_mask,
> +			       u32 enabled_irq_mask)
> +{
> +	u32 new_val;
> +
> +	lockdep_assert_held(&dev_priv->irq_lock);
> +	GEM_BUG_ON(enabled_irq_mask & ~interrupt_mask);
> +
> +	new_val = dev_priv->gt_pm.imr;
> +	new_val &= ~interrupt_mask;
> +	new_val |= ~enabled_irq_mask & interrupt_mask;
> +
> +	if (new_val != dev_priv->gt_pm.imr) {
> +		dev_priv->gt_pm.imr = new_val;
> +		I915_WRITE(gen6_pm_imr(dev_priv), dev_priv->gt_pm.imr);
> +	}
> +}
> +
> +static void gen6_reset_pm_iir(struct drm_i915_private *dev_priv,
> +			      u32 reset_mask)
> +{
> +	i915_reg_t reg = gen6_pm_iir(dev_priv);
> +
> +	lockdep_assert_held(&dev_priv->irq_lock);
> +
> +	I915_WRITE(reg, reset_mask);
> +	I915_WRITE(reg, reset_mask);
> +	POSTING_READ(reg);
> +}
> +
> +static void gen6_enable_pm_irq(struct drm_i915_private *dev_priv,
> +			       u32 enable_mask)
> +{
> +	lockdep_assert_held(&dev_priv->irq_lock);
> +
> +	dev_priv->gt_pm.ier |= enable_mask;
> +	I915_WRITE(gen6_pm_ier(dev_priv), dev_priv->gt_pm.ier);
> +	gen6_unmask_pm_irq(dev_priv, enable_mask);
> +	/* unmask_pm_irq provides an implicit barrier (POSTING_READ) */
> +}
> +
> +static void gen6_disable_pm_irq(struct drm_i915_private *dev_priv,
> +				u32 disable_mask)
> +{
> +	lockdep_assert_held(&dev_priv->irq_lock);
> +
> +	dev_priv->gt_pm.ier &= ~disable_mask;
> +	gen6_update_pm_irq(dev_priv, disable_mask, 0);
> +	I915_WRITE(gen6_pm_ier(dev_priv), dev_priv->gt_pm.ier);
> +	/* though a barrier is missing here, but don't really need a one */
> +}
> +
> +static void gen6_reset_rps_interrupts(struct drm_i915_private *dev_priv)
> +{
> +	struct intel_rps *rps = &dev_priv->gt_pm.rps;
> +
> +	spin_lock_irq(&dev_priv->irq_lock);
> +	gen6_reset_pm_iir(dev_priv, rps->pm_events);
> +	rps->pm_iir = 0;
> +	spin_unlock_irq(&dev_priv->irq_lock);
> +}
> +
> +static void enable_rps_interrupts(struct drm_i915_private *dev_priv)
> +{
> +	struct intel_rps *rps = &dev_priv->gt_pm.rps;
> +
> +	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)) & rps->pm_events);
> +	rps->interrupts_enabled = true;
> +	gen6_enable_pm_irq(dev_priv, rps->pm_events);
> +
> +	spin_unlock_irq(&dev_priv->irq_lock);
> +}
> +
> +static void disable_rps_interrupts(struct drm_i915_private *dev_priv)
> +{
> +	struct intel_rps *rps = &dev_priv->gt_pm.rps;
> +
> +	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;
> +
> +	I915_WRITE(GEN6_PMINTRMSK, gen6_sanitize_rps_pm_mask(dev_priv, ~0u));
> +
> +	gen6_disable_pm_irq(dev_priv, rps->pm_events);
> +
> +	spin_unlock_irq(&dev_priv->irq_lock);
> +	synchronize_irq(dev_priv->drm.irq);
> +
> +	/* Now that we will not be generating any more work, flush any
> +	 * outstanding tasks. As we are called on the RPS idle path,
> +	 * we will reset the GPU to minimum frequencies, so the current
> +	 * state of the worker can be discarded.
> +	 */
> +	cancel_work_sync(&rps->work);
> +	gen6_reset_rps_interrupts(dev_priv);
> +}
> +
>   static void vlv_c0_read(struct drm_i915_private *dev_priv,
>   			struct intel_rps_ei *ei)
>   {
> @@ -499,7 +625,7 @@ static void intel_rps_work(struct work_struct *work)
>   	bool client_boost;
>   	u32 pm_iir;
>   
> -	pm_iir = xchg(&rps->pm_iir, 0) & ~i915->pm_rps_events;
> +	pm_iir = xchg(&rps->pm_iir, 0) & ~rps->pm_events;
>   	pm_iir |= vlv_wa_c0_ei(i915, pm_iir);
>   
>   	client_boost = atomic_read(&rps->num_waiters);
> @@ -559,12 +685,27 @@ static void intel_rps_work(struct work_struct *work)
>   	if (pm_iir) {
>   		spin_lock_irq(&i915->irq_lock);
>   		if (rps->interrupts_enabled)
> -			gen6_unmask_pm_irq(i915, i915->pm_rps_events);
> +			gen6_unmask_pm_irq(i915, rps->pm_events);
>   		spin_unlock_irq(&i915->irq_lock);
>   		rps->last_adj = adj;
>   	}
>   }
>   
> +void intel_gt_pm_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
> +{
> +	struct intel_rps *rps = &dev_priv->gt_pm.rps;
> +
> +	if (pm_iir & rps->pm_events) {
> +		spin_lock(&dev_priv->irq_lock);
> +		gen6_mask_pm_irq(dev_priv, pm_iir & rps->pm_events);
> +		if (rps->interrupts_enabled) {
> +			rps->pm_iir |= pm_iir & rps->pm_events;
> +			schedule_work(&rps->work);
> +		}
> +		spin_unlock(&dev_priv->irq_lock);
> +	}
> +}
> +
>   void gen6_rps_busy(struct drm_i915_private *dev_priv)
>   {
>   	struct intel_rps *rps = &dev_priv->gt_pm.rps;
> @@ -576,7 +717,7 @@ void gen6_rps_busy(struct drm_i915_private *dev_priv)
>   		I915_WRITE(GEN6_PMINTRMSK,
>   			   gen6_rps_pm_mask(dev_priv, rps->cur_freq));
>   
> -		gen6_enable_rps_interrupts(dev_priv);
> +		enable_rps_interrupts(dev_priv);
>   		memset(&rps->ei, 0, sizeof(rps->ei));
>   
>   		/*
> @@ -605,7 +746,7 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv)
>   	 * our rpm wakeref. And then disable the interrupts to stop any
>   	 * futher RPS reclocking whilst we are asleep.
>   	 */
> -	gen6_disable_rps_interrupts(dev_priv);
> +	disable_rps_interrupts(dev_priv);
>   
>   	mutex_lock(&rps->lock);
>   	if (rps->enabled) {
> @@ -2238,6 +2379,30 @@ void intel_init_gt_powersave(struct drm_i915_private *dev_priv)
>   	mutex_init(&rps->lock);
>   	INIT_WORK(&rps->work, intel_rps_work);
>   
> +	if (HAS_GUC_SCHED(dev_priv))
> +		rps->guc_events = GEN9_GUC_TO_HOST_INT_EVENT;
> +
> +	/* Let's track the enabled rps events */
> +	if (IS_VALLEYVIEW(dev_priv))
> +		/* WaGsvRC0ResidencyMethod:vlv */
> +		rps->pm_events = GEN6_PM_RP_UP_EI_EXPIRED;
> +	else
> +		rps->pm_events = GEN6_PM_RPS_EVENTS;
> +
> +	rps->pm_intrmsk_mbz = 0;
> +
> +	/*
> +	 * SNB,IVB,HSW can while VLV,CHV may hard hang on looping batchbuffer
> +	 * if GEN6_PM_UP_EI_EXPIRED is masked.
> +	 *
> +	 * TODO: verify if this can be reproduced on VLV,CHV.
> +	 */
> +	if (INTEL_GEN(dev_priv) <= 7)
> +		rps->pm_intrmsk_mbz |= GEN6_PM_RP_UP_EI_EXPIRED;
> +
> +	if (INTEL_GEN(dev_priv) >= 8)
> +		rps->pm_intrmsk_mbz |= GEN8_PMINTR_DISABLE_REDIRECT_TO_GUC;
> +
>   	/*
>   	 * RPM depends on RC6 to save restore the GT HW context, so make RC6 a
>   	 * requirement.
> @@ -2538,3 +2703,51 @@ int intel_freq_opcode(struct drm_i915_private *dev_priv, int val)
>   	else
>   		return DIV_ROUND_CLOSEST(val, GT_FREQUENCY_MULTIPLIER);
>   }
> +
> +void gen6_unmask_pm_irq(struct drm_i915_private *dev_priv, u32 mask)
> +{
> +	gen6_update_pm_irq(dev_priv, mask, mask);
> +}
> +
> +void gen6_mask_pm_irq(struct drm_i915_private *dev_priv, u32 mask)
> +{
> +	gen6_update_pm_irq(dev_priv, mask, 0);
> +}
> +
> +void gen9_reset_guc_interrupts(struct drm_i915_private *dev_priv)
> +{
> +	assert_rpm_wakelock_held(dev_priv);
> +
> +	spin_lock_irq(&dev_priv->irq_lock);
> +	gen6_reset_pm_iir(dev_priv, dev_priv->gt_pm.rps.guc_events);
> +	spin_unlock_irq(&dev_priv->irq_lock);
> +}
> +
> +void gen9_enable_guc_interrupts(struct drm_i915_private *dev_priv)
> +{
> +	assert_rpm_wakelock_held(dev_priv);
> +
> +	spin_lock_irq(&dev_priv->irq_lock);
> +	if (!dev_priv->guc.interrupts_enabled) {
> +		WARN_ON_ONCE(I915_READ(gen6_pm_iir(dev_priv)) &
> +				       dev_priv->gt_pm.rps.guc_events);
> +		dev_priv->guc.interrupts_enabled = true;
> +		gen6_enable_pm_irq(dev_priv, dev_priv->gt_pm.rps.guc_events);
> +	}
> +	spin_unlock_irq(&dev_priv->irq_lock);
> +}
> +
> +void gen9_disable_guc_interrupts(struct drm_i915_private *dev_priv)
> +{
> +	assert_rpm_wakelock_held(dev_priv);
> +
> +	spin_lock_irq(&dev_priv->irq_lock);
> +	dev_priv->guc.interrupts_enabled = false;
> +
> +	gen6_disable_pm_irq(dev_priv, dev_priv->gt_pm.rps.guc_events);
> +
> +	spin_unlock_irq(&dev_priv->irq_lock);
> +	synchronize_irq(dev_priv->drm.irq);
> +
> +	gen9_reset_guc_interrupts(dev_priv);
> +}
> diff --git a/drivers/gpu/drm/i915/intel_gt_pm.h b/drivers/gpu/drm/i915/intel_gt_pm.h
> index f760226e5048..5ac16b614f8b 100644
> --- a/drivers/gpu/drm/i915/intel_gt_pm.h
> +++ b/drivers/gpu/drm/i915/intel_gt_pm.h
> @@ -38,6 +38,8 @@ void intel_enable_gt_powersave(struct drm_i915_private *dev_priv);
>   void intel_disable_gt_powersave(struct drm_i915_private *dev_priv);
>   void intel_suspend_gt_powersave(struct drm_i915_private *dev_priv);
>   
> +void intel_gt_pm_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir);
> +
>   void gen6_rps_busy(struct drm_i915_private *dev_priv);
>   void gen6_rps_idle(struct drm_i915_private *dev_priv);
>   void gen6_rps_boost(struct i915_request *rq, struct intel_rps_client *rps);
> @@ -45,4 +47,7 @@ void gen6_rps_boost(struct i915_request *rq, struct intel_rps_client *rps);
>   int intel_gpu_freq(struct drm_i915_private *dev_priv, int val);
>   int intel_freq_opcode(struct drm_i915_private *dev_priv, int val);
>   
> +void gen6_unmask_pm_irq(struct drm_i915_private *dev_priv, u32 mask);
> +void gen6_mask_pm_irq(struct drm_i915_private *dev_priv, u32 mask);
> +
>   #endif /* __INTEL_GT_PM_H__ */
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
> index 94fb93905ef6..1eed0254294d 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> @@ -36,6 +36,7 @@
>   #include "i915_gem_render_state.h"
>   #include "i915_trace.h"
>   #include "intel_drv.h"
> +#include "intel_gt_pm.h"
>   
>   /* Rough estimate of the typical request size, performing a flush,
>    * set-context and then emitting the batch.

-- 
Thanks,
Sagar



More information about the Intel-gfx mailing list