[Intel-gfx] [PATCH v2.1 2/3] drm/i915: Add GT support for multiple types of multicast steering

Matt Roper matthew.d.roper at intel.com
Wed Jun 16 16:30:40 UTC 2021


On Wed, Jun 16, 2021 at 10:24:48AM -0400, Rodrigo Vivi wrote:
> On Tue, Jun 15, 2021 at 05:42:12PM -0700, Matt Roper wrote:
> > Although most of our multicast registers are replicated per-subslice, we
> > also have a small number of multicast registers that are replicated
> > per-l3 bank instead.  For both types of multicast registers we need to
> > make sure we steer reads of these registers to a valid instance.
> > Ideally we'd like to find a specific instance ID that would steer reads
> > of either type of multicast register to a valid instance (i.e., not
> > fused off and not powered down), but sometimes the combination of
> > part-specific fusing and the additional restrictions imposed by Render
> > Power Gating make it impossible to find any overlap between the set of
> > valid subslices and valid l3 banks.  This problem will become even more
> > noticeable on our upcoming platforms since they will be adding
> > additional types of multicast registers with new types of replication
> > and rules for finding valid instances for reads.
> > 
> > To handle this we'll continue to pick a suitable subslice instance at
> > driver startup and program this as the default (sliceid,subsliceid)
> > setting in the steering control register (0xFDC).  In cases where we
> > need to read another type of multicast GT register, but the default
> > subslice steering would not correspond to a valid instance, we'll
> > explicitly re-steer the single read to a valid value, perform the read,
> > and then reset the steering to it's "subslice" default.
> > 
> > This patch adds the general functionality to prepare for this explicit
> > steering of other multicast register types.  We'll plug L3 bank steering
> > into this in the next patch, and then add additional types of multicast
> > registers when the support for our next upcoming platform arrives.
> > 
> > v2:
> >  - Use entry->end==0 as table terminator.  (Rodrigo)
> >  - Grab forcewake in wa_list_verify() now that we're using accessors
> >    that assume forcewake is already held.
> > 
> > Cc: Rodrigo Vivi <rodrigo.vivi at intel.com>
> > Signed-off-by: Matt Roper <matthew.d.roper at intel.com>
> > ---
> >  drivers/gpu/drm/i915/gt/intel_gt.c            | 84 +++++++++++++++++++
> >  drivers/gpu/drm/i915/gt/intel_gt.h            |  8 ++
> >  drivers/gpu/drm/i915/gt/intel_gt_types.h      | 22 +++++
> >  drivers/gpu/drm/i915/gt/intel_workarounds.c   | 39 ++++++---
> >  .../gpu/drm/i915/gt/selftest_workarounds.c    |  2 +-
> >  5 files changed, 142 insertions(+), 13 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c
> > index 2161bf01ef8b..66299105da66 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_gt.c
> > +++ b/drivers/gpu/drm/i915/gt/intel_gt.c
> > @@ -697,6 +697,90 @@ void intel_gt_driver_late_release(struct intel_gt *gt)
> >  	intel_engines_free(gt);
> >  }
> >  
> > +/**
> > + * intel_gt_reg_needs_read_steering - determine whether a register read
> > + *     requires explicit steering
> > + * @gt: GT structure
> > + * @reg: the register to check steering requirements for
> > + * @type: type of multicast steering to check
> > + *
> > + * Determines whether @reg needs explicit steering of a specific type for
> > + * reads.
> > + *
> > + * Returns false if @reg does not belong to a register range of the given
> > + * steering type, or if the default (subslice-based) steering IDs are suitable
> > + * for @type steering too.
> > + */
> > +static bool intel_gt_reg_needs_read_steering(struct intel_gt *gt,
> > +					     i915_reg_t reg,
> > +					     enum intel_steering_type type)
> > +{
> > +	const u32 offset = i915_mmio_reg_offset(reg);
> > +	const struct intel_mmio_range *entry;
> > +
> > +	if (likely(!intel_gt_needs_read_steering(gt, type)))
> > +		return false;
> > +
> > +	for (entry = gt->steering_table[type]; !entry->end; entry++) {
> 
> shouldn't it be:
> for (entry = gt->steering_table[type]; entry->end; entry++) {
> ?!

Yep, good catch.  I'll fix this.


Matt

> 
> or maybe this is just the proof that the 0xFFFF terminator
> is less confusing?! :)
> 
> with this fixed:
> 
> Reviewed-by: Rodrigo Vivi <rodrigo.vivi at intel.com>
> 
> > +		if (offset >= entry->start && offset <= entry->end)
> > +			return true;
> > +	}
> > +
> > +	return false;
> > +}
> > +
> > +/**
> > + * intel_gt_get_valid_steering - determines valid IDs for a class of MCR steering
> > + * @gt: GT structure
> > + * @type: multicast register type
> > + * @sliceid: Slice ID returned
> > + * @subsliceid: Subslice ID returned
> > + *
> > + * Determines sliceid and subsliceid values that will steer reads
> > + * of a specific multicast register class to a valid value.
> > + */
> > +static void intel_gt_get_valid_steering(struct intel_gt *gt,
> > +					enum intel_steering_type type,
> > +					u8 *sliceid, u8 *subsliceid)
> > +{
> > +	switch (type) {
> > +	default:
> > +		MISSING_CASE(type);
> > +		*sliceid = 0;
> > +		*subsliceid = 0;
> > +	}
> > +}
> > +
> > +/**
> > + * intel_gt_read_register_fw - reads a GT register with support for multicast
> > + * @gt: GT structure
> > + * @reg: register to read
> > + *
> > + * This function will read a GT register.  If the register is a multicast
> > + * register, the read will be steered to a valid instance (i.e., one that
> > + * isn't fused off or powered down by power gating).
> > + *
> > + * Returns the value from a valid instance of @reg.
> > + */
> > +u32 intel_gt_read_register_fw(struct intel_gt *gt, i915_reg_t reg)
> > +{
> > +	int type;
> > +	u8 sliceid, subsliceid;
> > +
> > +	for (type = 0; type < NUM_STEERING_TYPES; type++) {
> > +		if (intel_gt_reg_needs_read_steering(gt, reg, type)) {
> > +			intel_gt_get_valid_steering(gt, type, &sliceid,
> > +						    &subsliceid);
> > +			return intel_uncore_read_with_mcr_steering_fw(gt->uncore,
> > +								      reg,
> > +								      sliceid,
> > +								      subsliceid);
> > +		}
> > +	}
> > +
> > +	return intel_uncore_read_fw(gt->uncore, reg);
> > +}
> > +
> >  void intel_gt_info_print(const struct intel_gt_info *info,
> >  			 struct drm_printer *p)
> >  {
> > diff --git a/drivers/gpu/drm/i915/gt/intel_gt.h b/drivers/gpu/drm/i915/gt/intel_gt.h
> > index 7ec395cace69..e7aabe0cc5bf 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_gt.h
> > +++ b/drivers/gpu/drm/i915/gt/intel_gt.h
> > @@ -75,6 +75,14 @@ static inline bool intel_gt_is_wedged(const struct intel_gt *gt)
> >  	return unlikely(test_bit(I915_WEDGED, &gt->reset.flags));
> >  }
> >  
> > +static inline bool intel_gt_needs_read_steering(struct intel_gt *gt,
> > +						enum intel_steering_type type)
> > +{
> > +	return gt->steering_table[type];
> > +}
> > +
> > +u32 intel_gt_read_register_fw(struct intel_gt *gt, i915_reg_t reg);
> > +
> >  void intel_gt_info_print(const struct intel_gt_info *info,
> >  			 struct drm_printer *p);
> >  
> > diff --git a/drivers/gpu/drm/i915/gt/intel_gt_types.h b/drivers/gpu/drm/i915/gt/intel_gt_types.h
> > index fecfacf551d5..f2c274eee1e6 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_gt_types.h
> > +++ b/drivers/gpu/drm/i915/gt/intel_gt_types.h
> > @@ -31,6 +31,26 @@ struct i915_ggtt;
> >  struct intel_engine_cs;
> >  struct intel_uncore;
> >  
> > +struct intel_mmio_range {
> > +	u32 start;
> > +	u32 end;
> > +};
> > +
> > +/*
> > + * The hardware has multiple kinds of multicast register ranges that need
> > + * special register steering (and future platforms are expected to add
> > + * additional types).
> > + *
> > + * During driver startup, we initialize the steering control register to
> > + * direct reads to a slice/subslice that are valid for the 'subslice' class
> > + * of multicast registers.  If another type of steering does not have any
> > + * overlap in valid steering targets with 'subslice' style registers, we will
> > + * need to explicitly re-steer reads of registers of the other type.
> > + */
> > +enum intel_steering_type {
> > +	NUM_STEERING_TYPES
> > +};
> > +
> >  enum intel_submission_method {
> >  	INTEL_SUBMISSION_RING,
> >  	INTEL_SUBMISSION_ELSP,
> > @@ -145,6 +165,8 @@ struct intel_gt {
> >  
> >  	struct i915_vma *scratch;
> >  
> > +	const struct intel_mmio_range *steering_table[NUM_STEERING_TYPES];
> > +
> >  	struct intel_gt_info {
> >  		intel_engine_mask_t engine_mask;
> >  		u8 num_engines;
> > diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c
> > index 977a76e648e0..93c74d4cae02 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c
> > +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c
> > @@ -1248,8 +1248,9 @@ wa_verify(const struct i915_wa *wa, u32 cur, const char *name, const char *from)
> >  }
> >  
> >  static void
> > -wa_list_apply(struct intel_uncore *uncore, const struct i915_wa_list *wal)
> > +wa_list_apply(struct intel_gt *gt, const struct i915_wa_list *wal)
> >  {
> > +	struct intel_uncore *uncore = gt->uncore;
> >  	enum forcewake_domains fw;
> >  	unsigned long flags;
> >  	struct i915_wa *wa;
> > @@ -1264,13 +1265,16 @@ wa_list_apply(struct intel_uncore *uncore, const struct i915_wa_list *wal)
> >  	intel_uncore_forcewake_get__locked(uncore, fw);
> >  
> >  	for (i = 0, wa = wal->list; i < wal->count; i++, wa++) {
> > -		if (wa->clr)
> > -			intel_uncore_rmw_fw(uncore, wa->reg, wa->clr, wa->set);
> > -		else
> > -			intel_uncore_write_fw(uncore, wa->reg, wa->set);
> > +		u32 val, old = 0;
> > +
> > +		/* open-coded rmw due to steering */
> > +		old = wa->clr ? intel_gt_read_register_fw(gt, wa->reg) : 0;
> > +		val = (old & ~wa->clr) | wa->set;
> > +		if (val != old || !wa->clr)
> > +			intel_uncore_write_fw(uncore, wa->reg, val);
> > +
> >  		if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM))
> > -			wa_verify(wa,
> > -				  intel_uncore_read_fw(uncore, wa->reg),
> > +			wa_verify(wa, intel_gt_read_register_fw(gt, wa->reg),
> >  				  wal->name, "application");
> >  	}
> >  
> > @@ -1280,28 +1284,39 @@ wa_list_apply(struct intel_uncore *uncore, const struct i915_wa_list *wal)
> >  
> >  void intel_gt_apply_workarounds(struct intel_gt *gt)
> >  {
> > -	wa_list_apply(gt->uncore, &gt->i915->gt_wa_list);
> > +	wa_list_apply(gt, &gt->i915->gt_wa_list);
> >  }
> >  
> > -static bool wa_list_verify(struct intel_uncore *uncore,
> > +static bool wa_list_verify(struct intel_gt *gt,
> >  			   const struct i915_wa_list *wal,
> >  			   const char *from)
> >  {
> > +	struct intel_uncore *uncore = gt->uncore;
> >  	struct i915_wa *wa;
> > +	enum forcewake_domains fw;
> > +	unsigned long flags;
> >  	unsigned int i;
> >  	bool ok = true;
> >  
> > +	fw = wal_get_fw_for_rmw(uncore, wal);
> > +
> > +	spin_lock_irqsave(&uncore->lock, flags);
> > +	intel_uncore_forcewake_get__locked(uncore, fw);
> > +
> >  	for (i = 0, wa = wal->list; i < wal->count; i++, wa++)
> >  		ok &= wa_verify(wa,
> > -				intel_uncore_read(uncore, wa->reg),
> > +				intel_gt_read_register_fw(gt, wa->reg),
> >  				wal->name, from);
> >  
> > +	intel_uncore_forcewake_put__locked(uncore, fw);
> > +	spin_unlock_irqrestore(&uncore->lock, flags);
> > +
> >  	return ok;
> >  }
> >  
> >  bool intel_gt_verify_workarounds(struct intel_gt *gt, const char *from)
> >  {
> > -	return wa_list_verify(gt->uncore, &gt->i915->gt_wa_list, from);
> > +	return wa_list_verify(gt, &gt->i915->gt_wa_list, from);
> >  }
> >  
> >  __maybe_unused
> > @@ -2084,7 +2099,7 @@ void intel_engine_init_workarounds(struct intel_engine_cs *engine)
> >  
> >  void intel_engine_apply_workarounds(struct intel_engine_cs *engine)
> >  {
> > -	wa_list_apply(engine->uncore, &engine->wa_list);
> > +	wa_list_apply(engine->gt, &engine->wa_list);
> >  }
> >  
> >  struct mcr_range {
> > diff --git a/drivers/gpu/drm/i915/gt/selftest_workarounds.c b/drivers/gpu/drm/i915/gt/selftest_workarounds.c
> > index c30754daf4b1..7ebc4edb8ecf 100644
> > --- a/drivers/gpu/drm/i915/gt/selftest_workarounds.c
> > +++ b/drivers/gpu/drm/i915/gt/selftest_workarounds.c
> > @@ -1147,7 +1147,7 @@ verify_wa_lists(struct intel_gt *gt, struct wa_lists *lists,
> >  	enum intel_engine_id id;
> >  	bool ok = true;
> >  
> > -	ok &= wa_list_verify(gt->uncore, &lists->gt_wa_list, str);
> > +	ok &= wa_list_verify(gt, &lists->gt_wa_list, str);
> >  
> >  	for_each_engine(engine, gt, id) {
> >  		struct intel_context *ce;
> > -- 
> > 2.25.4
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx at lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Matt Roper
Graphics Software Engineer
VTT-OSGC Platform Enablement
Intel Corporation
(916) 356-2795


More information about the Intel-gfx mailing list