All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
To: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>,
	intel-gfx@lists.freedesktop.org
Subject: Re: [Intel-gfx] [PATCH 6/7] drm/i915/sseu: Move sseu detection and dump to intel_sseu
Date: Fri, 26 Jun 2020 16:00:53 +0100	[thread overview]
Message-ID: <841291ae-40d8-c430-dbc8-6b16f7fbc713@linux.intel.com> (raw)
In-Reply-To: <20200625234212.22811-7-daniele.ceraolospurio@intel.com>


On 26/06/2020 00:42, Daniele Ceraolo Spurio wrote:
> Keep all the SSEU code in the relevant file. The code has also been
> updated to use intel_gt instead of dev_priv.
> 
> Based on an original patch by Sandeep.
> 
> Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
> Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
> Cc: Andi Shyti <andi.shyti@intel.com>
> Cc: Venkata Sandeep Dhanalakota <venkata.s.dhanalakota@intel.com>
> ---
>   drivers/gpu/drm/i915/gt/intel_gt.c       |   1 +
>   drivers/gpu/drm/i915/gt/intel_sseu.c     | 587 +++++++++++++++++++++++
>   drivers/gpu/drm/i915/gt/intel_sseu.h     |   8 +
>   drivers/gpu/drm/i915/i915_debugfs.c      |   2 +-
>   drivers/gpu/drm/i915/i915_gpu_error.c    |   2 +-
>   drivers/gpu/drm/i915/intel_device_info.c | 584 +---------------------
>   drivers/gpu/drm/i915/intel_device_info.h |   2 -
>   7 files changed, 600 insertions(+), 586 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c
> index 949114f09b82..de95930f8627 100644
> --- a/drivers/gpu/drm/i915/gt/intel_gt.c
> +++ b/drivers/gpu/drm/i915/gt/intel_gt.c
> @@ -47,6 +47,7 @@ void intel_gt_init_hw_early(struct intel_gt *gt, struct i915_ggtt *ggtt)
>   int intel_gt_init_mmio(struct intel_gt *gt)
>   {
>   	intel_uc_init_mmio(&gt->uc);
> +	intel_sseu_info_init(gt);
>   
>   	return intel_engines_init_mmio(gt);
>   }
> diff --git a/drivers/gpu/drm/i915/gt/intel_sseu.c b/drivers/gpu/drm/i915/gt/intel_sseu.c
> index d173271c7397..006f9118b319 100644
> --- a/drivers/gpu/drm/i915/gt/intel_sseu.c
> +++ b/drivers/gpu/drm/i915/gt/intel_sseu.c
> @@ -60,6 +60,548 @@ intel_sseu_subslices_per_slice(const struct sseu_dev_info *sseu, u8 slice)
>   	return hweight32(intel_sseu_get_subslices(sseu, slice));
>   }
>   
> +static int sseu_eu_idx(const struct sseu_dev_info *sseu, int slice,
> +		       int subslice)
> +{
> +	int slice_stride = sseu->max_subslices * sseu->eu_stride;
> +
> +	return slice * slice_stride + subslice * sseu->eu_stride;
> +}
> +
> +static u16 sseu_get_eus(const struct sseu_dev_info *sseu, int slice,
> +			int subslice)
> +{
> +	int i, offset = sseu_eu_idx(sseu, slice, subslice);
> +	u16 eu_mask = 0;
> +
> +	for (i = 0; i < sseu->eu_stride; i++) {
> +		eu_mask |= ((u16)sseu->eu_mask[offset + i]) <<
> +			(i * BITS_PER_BYTE);
> +	}
> +
> +	return eu_mask;
> +}
> +
> +static void sseu_set_eus(struct sseu_dev_info *sseu, int slice, int subslice,
> +			 u16 eu_mask)
> +{
> +	int i, offset = sseu_eu_idx(sseu, slice, subslice);
> +
> +	for (i = 0; i < sseu->eu_stride; i++) {
> +		sseu->eu_mask[offset + i] =
> +			(eu_mask >> (BITS_PER_BYTE * i)) & 0xff;
> +	}
> +}
> +
> +static u16 compute_eu_total(const struct sseu_dev_info *sseu)
> +{
> +	u16 i, total = 0;
> +
> +	for (i = 0; i < ARRAY_SIZE(sseu->eu_mask); i++)
> +		total += hweight8(sseu->eu_mask[i]);
> +
> +	return total;
> +}
> +
> +static void gen11_compute_sseu_info(struct sseu_dev_info *sseu,
> +				    u8 s_en, u32 ss_en, u16 eu_en)
> +{
> +	int s, ss;
> +
> +	/* ss_en represents entire subslice mask across all slices */
> +	GEM_BUG_ON(sseu->max_slices * sseu->max_subslices >
> +		   sizeof(ss_en) * BITS_PER_BYTE);
> +
> +	for (s = 0; s < sseu->max_slices; s++) {
> +		if ((s_en & BIT(s)) == 0)
> +			continue;
> +
> +		sseu->slice_mask |= BIT(s);
> +
> +		intel_sseu_set_subslices(sseu, s, ss_en);
> +
> +		for (ss = 0; ss < sseu->max_subslices; ss++)
> +			if (intel_sseu_has_subslice(sseu, s, ss))
> +				sseu_set_eus(sseu, s, ss, eu_en);
> +	}
> +	sseu->eu_per_subslice = hweight16(eu_en);
> +	sseu->eu_total = compute_eu_total(sseu);
> +}
> +
> +static void gen12_sseu_info_init(struct intel_gt *gt)
> +{
> +	struct sseu_dev_info *sseu = &RUNTIME_INFO(gt->i915)->sseu;
> +	struct intel_uncore *uncore = gt->uncore;
> +	u8 s_en;
> +	u32 dss_en;
> +	u16 eu_en = 0;
> +	u8 eu_en_fuse;
> +	int eu;
> +
> +	/*
> +	 * Gen12 has Dual-Subslices, which behave similarly to 2 gen11 SS.
> +	 * Instead of splitting these, provide userspace with an array
> +	 * of DSS to more closely represent the hardware resource.
> +	 */
> +	intel_sseu_set_info(sseu, 1, 6, 16);
> +
> +	s_en = intel_uncore_read(uncore, GEN11_GT_SLICE_ENABLE) &
> +	       GEN11_GT_S_ENA_MASK;
> +
> +	dss_en = intel_uncore_read(uncore, GEN12_GT_DSS_ENABLE);
> +
> +	/* one bit per pair of EUs */
> +	eu_en_fuse = ~(intel_uncore_read(uncore, GEN11_EU_DISABLE) &
> +		       GEN11_EU_DIS_MASK);
> +	for (eu = 0; eu < sseu->max_eus_per_subslice / 2; eu++)
> +		if (eu_en_fuse & BIT(eu))
> +			eu_en |= BIT(eu * 2) | BIT(eu * 2 + 1);
> +
> +	gen11_compute_sseu_info(sseu, s_en, dss_en, eu_en);
> +
> +	/* TGL only supports slice-level power gating */
> +	sseu->has_slice_pg = 1;
> +}
> +
> +static void gen11_sseu_info_init(struct intel_gt *gt)
> +{
> +	struct sseu_dev_info *sseu = &RUNTIME_INFO(gt->i915)->sseu;
> +	struct intel_uncore *uncore = gt->uncore;
> +	u8 s_en;
> +	u32 ss_en;
> +	u8 eu_en;
> +
> +	if (IS_ELKHARTLAKE(gt->i915))
> +		intel_sseu_set_info(sseu, 1, 4, 8);
> +	else
> +		intel_sseu_set_info(sseu, 1, 8, 8);
> +
> +	s_en = intel_uncore_read(uncore, GEN11_GT_SLICE_ENABLE) &
> +	       GEN11_GT_S_ENA_MASK;
> +	ss_en = ~intel_uncore_read(uncore, GEN11_GT_SUBSLICE_DISABLE);
> +
> +	eu_en = ~(intel_uncore_read(uncore, GEN11_EU_DISABLE) &
> +		  GEN11_EU_DIS_MASK);
> +
> +	gen11_compute_sseu_info(sseu, s_en, ss_en, eu_en);
> +
> +	/* ICL has no power gating restrictions. */
> +	sseu->has_slice_pg = 1;
> +	sseu->has_subslice_pg = 1;
> +	sseu->has_eu_pg = 1;
> +}
> +
> +static void gen10_sseu_info_init(struct intel_gt *gt)
> +{
> +	struct intel_uncore *uncore = gt->uncore;
> +	struct sseu_dev_info *sseu = &RUNTIME_INFO(gt->i915)->sseu;
> +	const u32 fuse2 = intel_uncore_read(uncore, GEN8_FUSE2);
> +	int s, ss;
> +	const int eu_mask = 0xff;
> +	u32 subslice_mask, eu_en;
> +
> +	intel_sseu_set_info(sseu, 6, 4, 8);
> +
> +	sseu->slice_mask = (fuse2 & GEN10_F2_S_ENA_MASK) >>
> +			    GEN10_F2_S_ENA_SHIFT;
> +
> +	/* Slice0 */
> +	eu_en = ~intel_uncore_read(uncore, GEN8_EU_DISABLE0);
> +	for (ss = 0; ss < sseu->max_subslices; ss++)
> +		sseu_set_eus(sseu, 0, ss, (eu_en >> (8 * ss)) & eu_mask);
> +	/* Slice1 */
> +	sseu_set_eus(sseu, 1, 0, (eu_en >> 24) & eu_mask);
> +	eu_en = ~intel_uncore_read(uncore, GEN8_EU_DISABLE1);
> +	sseu_set_eus(sseu, 1, 1, eu_en & eu_mask);
> +	/* Slice2 */
> +	sseu_set_eus(sseu, 2, 0, (eu_en >> 8) & eu_mask);
> +	sseu_set_eus(sseu, 2, 1, (eu_en >> 16) & eu_mask);
> +	/* Slice3 */
> +	sseu_set_eus(sseu, 3, 0, (eu_en >> 24) & eu_mask);
> +	eu_en = ~intel_uncore_read(uncore, GEN8_EU_DISABLE2);
> +	sseu_set_eus(sseu, 3, 1, eu_en & eu_mask);
> +	/* Slice4 */
> +	sseu_set_eus(sseu, 4, 0, (eu_en >> 8) & eu_mask);
> +	sseu_set_eus(sseu, 4, 1, (eu_en >> 16) & eu_mask);
> +	/* Slice5 */
> +	sseu_set_eus(sseu, 5, 0, (eu_en >> 24) & eu_mask);
> +	eu_en = ~intel_uncore_read(uncore, GEN10_EU_DISABLE3);
> +	sseu_set_eus(sseu, 5, 1, eu_en & eu_mask);
> +
> +	subslice_mask = (1 << 4) - 1;
> +	subslice_mask &= ~((fuse2 & GEN10_F2_SS_DIS_MASK) >>
> +			   GEN10_F2_SS_DIS_SHIFT);
> +
> +	for (s = 0; s < sseu->max_slices; s++) {
> +		u32 subslice_mask_with_eus = subslice_mask;
> +
> +		for (ss = 0; ss < sseu->max_subslices; ss++) {
> +			if (sseu_get_eus(sseu, s, ss) == 0)
> +				subslice_mask_with_eus &= ~BIT(ss);
> +		}
> +
> +		/*
> +		 * Slice0 can have up to 3 subslices, but there are only 2 in
> +		 * slice1/2.
> +		 */
> +		intel_sseu_set_subslices(sseu, s, s == 0 ?
> +						  subslice_mask_with_eus :
> +						  subslice_mask_with_eus & 0x3);
> +	}
> +
> +	sseu->eu_total = compute_eu_total(sseu);
> +
> +	/*
> +	 * CNL is expected to always have a uniform distribution
> +	 * of EU across subslices with the exception that any one
> +	 * EU in any one subslice may be fused off for die
> +	 * recovery.
> +	 */
> +	sseu->eu_per_subslice = intel_sseu_subslice_total(sseu) ?
> +				DIV_ROUND_UP(sseu->eu_total,
> +					     intel_sseu_subslice_total(sseu)) :
> +				0;
> +
> +	/* No restrictions on Power Gating */
> +	sseu->has_slice_pg = 1;
> +	sseu->has_subslice_pg = 1;
> +	sseu->has_eu_pg = 1;
> +}
> +
> +static void cherryview_sseu_info_init(struct intel_gt *gt)
> +{
> +	struct sseu_dev_info *sseu = &RUNTIME_INFO(gt->i915)->sseu;
> +	u32 fuse;
> +	u8 subslice_mask = 0;
> +
> +	fuse = intel_uncore_read(gt->uncore, CHV_FUSE_GT);
> +
> +	sseu->slice_mask = BIT(0);
> +	intel_sseu_set_info(sseu, 1, 2, 8);
> +
> +	if (!(fuse & CHV_FGT_DISABLE_SS0)) {
> +		u8 disabled_mask =
> +			((fuse & CHV_FGT_EU_DIS_SS0_R0_MASK) >>
> +			 CHV_FGT_EU_DIS_SS0_R0_SHIFT) |
> +			(((fuse & CHV_FGT_EU_DIS_SS0_R1_MASK) >>
> +			  CHV_FGT_EU_DIS_SS0_R1_SHIFT) << 4);
> +
> +		subslice_mask |= BIT(0);
> +		sseu_set_eus(sseu, 0, 0, ~disabled_mask);
> +	}
> +
> +	if (!(fuse & CHV_FGT_DISABLE_SS1)) {
> +		u8 disabled_mask =
> +			((fuse & CHV_FGT_EU_DIS_SS1_R0_MASK) >>
> +			 CHV_FGT_EU_DIS_SS1_R0_SHIFT) |
> +			(((fuse & CHV_FGT_EU_DIS_SS1_R1_MASK) >>
> +			  CHV_FGT_EU_DIS_SS1_R1_SHIFT) << 4);
> +
> +		subslice_mask |= BIT(1);
> +		sseu_set_eus(sseu, 0, 1, ~disabled_mask);
> +	}
> +
> +	intel_sseu_set_subslices(sseu, 0, subslice_mask);
> +
> +	sseu->eu_total = compute_eu_total(sseu);
> +
> +	/*
> +	 * CHV expected to always have a uniform distribution of EU
> +	 * across subslices.
> +	*/
> +	sseu->eu_per_subslice = intel_sseu_subslice_total(sseu) ?
> +				sseu->eu_total /
> +					intel_sseu_subslice_total(sseu) :
> +				0;
> +	/*
> +	 * CHV supports subslice power gating on devices with more than
> +	 * one subslice, and supports EU power gating on devices with
> +	 * more than one EU pair per subslice.
> +	*/
> +	sseu->has_slice_pg = 0;
> +	sseu->has_subslice_pg = intel_sseu_subslice_total(sseu) > 1;
> +	sseu->has_eu_pg = (sseu->eu_per_subslice > 2);
> +}
> +
> +static void gen9_sseu_info_init(struct intel_gt *gt)
> +{
> +	struct drm_i915_private *i915 = gt->i915;
> +	struct intel_device_info *info = mkwrite_device_info(i915);
> +	struct sseu_dev_info *sseu = &RUNTIME_INFO(i915)->sseu;
> +	struct intel_uncore *uncore = gt->uncore;
> +	int s, ss;
> +	u32 fuse2, eu_disable, subslice_mask;
> +	const u8 eu_mask = 0xff;
> +
> +	fuse2 = intel_uncore_read(uncore, GEN8_FUSE2);
> +	sseu->slice_mask = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;
> +
> +	/* BXT has a single slice and at most 3 subslices. */
> +	intel_sseu_set_info(sseu, IS_GEN9_LP(i915) ? 1 : 3,
> +			    IS_GEN9_LP(i915) ? 3 : 4, 8);
> +
> +	/*
> +	 * The subslice disable field is global, i.e. it applies
> +	 * to each of the enabled slices.
> +	*/
> +	subslice_mask = (1 << sseu->max_subslices) - 1;
> +	subslice_mask &= ~((fuse2 & GEN9_F2_SS_DIS_MASK) >>
> +			   GEN9_F2_SS_DIS_SHIFT);
> +
> +	/*
> +	 * Iterate through enabled slices and subslices to
> +	 * count the total enabled EU.
> +	*/
> +	for (s = 0; s < sseu->max_slices; s++) {
> +		if (!(sseu->slice_mask & BIT(s)))
> +			/* skip disabled slice */
> +			continue;
> +
> +		intel_sseu_set_subslices(sseu, s, subslice_mask);
> +
> +		eu_disable = intel_uncore_read(uncore, GEN9_EU_DISABLE(s));
> +		for (ss = 0; ss < sseu->max_subslices; ss++) {
> +			int eu_per_ss;
> +			u8 eu_disabled_mask;
> +
> +			if (!intel_sseu_has_subslice(sseu, s, ss))
> +				/* skip disabled subslice */
> +				continue;
> +
> +			eu_disabled_mask = (eu_disable >> (ss * 8)) & eu_mask;
> +
> +			sseu_set_eus(sseu, s, ss, ~eu_disabled_mask);
> +
> +			eu_per_ss = sseu->max_eus_per_subslice -
> +				hweight8(eu_disabled_mask);
> +
> +			/*
> +			 * Record which subslice(s) has(have) 7 EUs. we
> +			 * can tune the hash used to spread work among
> +			 * subslices if they are unbalanced.
> +			 */
> +			if (eu_per_ss == 7)
> +				sseu->subslice_7eu[s] |= BIT(ss);
> +		}
> +	}
> +
> +	sseu->eu_total = compute_eu_total(sseu);
> +
> +	/*
> +	 * SKL is expected to always have a uniform distribution
> +	 * of EU across subslices with the exception that any one
> +	 * EU in any one subslice may be fused off for die
> +	 * recovery. BXT is expected to be perfectly uniform in EU
> +	 * distribution.
> +	*/
> +	sseu->eu_per_subslice = intel_sseu_subslice_total(sseu) ?
> +				DIV_ROUND_UP(sseu->eu_total,
> +					     intel_sseu_subslice_total(sseu)) :
> +				0;
> +	/*
> +	 * SKL+ supports slice power gating on devices with more than
> +	 * one slice, and supports EU power gating on devices with
> +	 * more than one EU pair per subslice. BXT+ supports subslice
> +	 * power gating on devices with more than one subslice, and
> +	 * supports EU power gating on devices with more than one EU
> +	 * pair per subslice.
> +	*/
> +	sseu->has_slice_pg =
> +		!IS_GEN9_LP(i915) && hweight8(sseu->slice_mask) > 1;
> +	sseu->has_subslice_pg =
> +		IS_GEN9_LP(i915) && intel_sseu_subslice_total(sseu) > 1;
> +	sseu->has_eu_pg = sseu->eu_per_subslice > 2;
> +
> +	if (IS_GEN9_LP(i915)) {
> +#define IS_SS_DISABLED(ss)	(!(sseu->subslice_mask[0] & BIT(ss)))
> +		info->has_pooled_eu = hweight8(sseu->subslice_mask[0]) == 3;
> +
> +		sseu->min_eu_in_pool = 0;
> +		if (info->has_pooled_eu) {
> +			if (IS_SS_DISABLED(2) || IS_SS_DISABLED(0))
> +				sseu->min_eu_in_pool = 3;
> +			else if (IS_SS_DISABLED(1))
> +				sseu->min_eu_in_pool = 6;
> +			else
> +				sseu->min_eu_in_pool = 9;
> +		}
> +#undef IS_SS_DISABLED
> +	}
> +}
> +
> +static void bdw_sseu_info_init(struct intel_gt *gt)
> +{
> +	struct sseu_dev_info *sseu = &RUNTIME_INFO(gt->i915)->sseu;
> +	struct intel_uncore *uncore = gt->uncore;
> +	int s, ss;
> +	u32 fuse2, subslice_mask, eu_disable[3]; /* s_max */
> +	u32 eu_disable0, eu_disable1, eu_disable2;
> +
> +	fuse2 = intel_uncore_read(uncore, GEN8_FUSE2);
> +	sseu->slice_mask = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;
> +	intel_sseu_set_info(sseu, 3, 3, 8);
> +
> +	/*
> +	 * The subslice disable field is global, i.e. it applies
> +	 * to each of the enabled slices.
> +	 */
> +	subslice_mask = GENMASK(sseu->max_subslices - 1, 0);
> +	subslice_mask &= ~((fuse2 & GEN8_F2_SS_DIS_MASK) >>
> +			   GEN8_F2_SS_DIS_SHIFT);
> +	eu_disable0 = intel_uncore_read(uncore, GEN8_EU_DISABLE0);
> +	eu_disable1 = intel_uncore_read(uncore, GEN8_EU_DISABLE1);
> +	eu_disable2 = intel_uncore_read(uncore, GEN8_EU_DISABLE2);
> +	eu_disable[0] = eu_disable0 & GEN8_EU_DIS0_S0_MASK;
> +	eu_disable[1] = (eu_disable0 >> GEN8_EU_DIS0_S1_SHIFT) |
> +			((eu_disable1 & GEN8_EU_DIS1_S1_MASK) <<
> +			 (32 - GEN8_EU_DIS0_S1_SHIFT));
> +	eu_disable[2] = (eu_disable1 >> GEN8_EU_DIS1_S2_SHIFT) |
> +			((eu_disable2 & GEN8_EU_DIS2_S2_MASK) <<
> +			 (32 - GEN8_EU_DIS1_S2_SHIFT));
> +
> +	/*
> +	 * Iterate through enabled slices and subslices to
> +	 * count the total enabled EU.
> +	 */
> +	for (s = 0; s < sseu->max_slices; s++) {
> +		if (!(sseu->slice_mask & BIT(s)))
> +			/* skip disabled slice */
> +			continue;
> +
> +		intel_sseu_set_subslices(sseu, s, subslice_mask);
> +
> +		for (ss = 0; ss < sseu->max_subslices; ss++) {
> +			u8 eu_disabled_mask;
> +			u32 n_disabled;
> +
> +			if (!intel_sseu_has_subslice(sseu, s, ss))
> +				/* skip disabled subslice */
> +				continue;
> +
> +			eu_disabled_mask =
> +				eu_disable[s] >> (ss * sseu->max_eus_per_subslice);
> +
> +			sseu_set_eus(sseu, s, ss, ~eu_disabled_mask);
> +
> +			n_disabled = hweight8(eu_disabled_mask);
> +
> +			/*
> +			 * Record which subslices have 7 EUs.
> +			 */
> +			if (sseu->max_eus_per_subslice - n_disabled == 7)
> +				sseu->subslice_7eu[s] |= 1 << ss;
> +		}
> +	}
> +
> +	sseu->eu_total = compute_eu_total(sseu);
> +
> +	/*
> +	 * BDW is expected to always have a uniform distribution of EU across
> +	 * subslices with the exception that any one EU in any one subslice may
> +	 * be fused off for die recovery.
> +	 */
> +	sseu->eu_per_subslice = intel_sseu_subslice_total(sseu) ?
> +				DIV_ROUND_UP(sseu->eu_total,
> +					     intel_sseu_subslice_total(sseu)) :
> +				0;
> +
> +	/*
> +	 * BDW supports slice power gating on devices with more than
> +	 * one slice.
> +	 */
> +	sseu->has_slice_pg = hweight8(sseu->slice_mask) > 1;
> +	sseu->has_subslice_pg = 0;
> +	sseu->has_eu_pg = 0;
> +}
> +
> +static void hsw_sseu_info_init(struct intel_gt *gt)
> +{
> +	struct drm_i915_private *i915 = gt->i915;
> +	struct sseu_dev_info *sseu = &RUNTIME_INFO(gt->i915)->sseu;
> +	u32 fuse1;
> +	u8 subslice_mask = 0;
> +	int s, ss;
> +
> +	/*
> +	 * There isn't a register to tell us how many slices/subslices. We
> +	 * work off the PCI-ids here.
> +	 */
> +	switch (INTEL_INFO(i915)->gt) {
> +	default:
> +		MISSING_CASE(INTEL_INFO(i915)->gt);
> +		/* fall through */
> +	case 1:
> +		sseu->slice_mask = BIT(0);
> +		subslice_mask = BIT(0);
> +		break;
> +	case 2:
> +		sseu->slice_mask = BIT(0);
> +		subslice_mask = BIT(0) | BIT(1);
> +		break;
> +	case 3:
> +		sseu->slice_mask = BIT(0) | BIT(1);
> +		subslice_mask = BIT(0) | BIT(1);
> +		break;
> +	}
> +
> +	fuse1 = intel_uncore_read(gt->uncore, HSW_PAVP_FUSE1);
> +	switch ((fuse1 & HSW_F1_EU_DIS_MASK) >> HSW_F1_EU_DIS_SHIFT) {
> +	default:
> +		MISSING_CASE((fuse1 & HSW_F1_EU_DIS_MASK) >>
> +			     HSW_F1_EU_DIS_SHIFT);
> +		/* fall through */
> +	case HSW_F1_EU_DIS_10EUS:
> +		sseu->eu_per_subslice = 10;
> +		break;
> +	case HSW_F1_EU_DIS_8EUS:
> +		sseu->eu_per_subslice = 8;
> +		break;
> +	case HSW_F1_EU_DIS_6EUS:
> +		sseu->eu_per_subslice = 6;
> +		break;
> +	}
> +
> +	intel_sseu_set_info(sseu, hweight8(sseu->slice_mask),
> +			    hweight8(subslice_mask),
> +			    sseu->eu_per_subslice);
> +
> +	for (s = 0; s < sseu->max_slices; s++) {
> +		intel_sseu_set_subslices(sseu, s, subslice_mask);
> +
> +		for (ss = 0; ss < sseu->max_subslices; ss++) {
> +			sseu_set_eus(sseu, s, ss,
> +				     (1UL << sseu->eu_per_subslice) - 1);
> +		}
> +	}
> +
> +	sseu->eu_total = compute_eu_total(sseu);
> +
> +	/* No powergating for you. */
> +	sseu->has_slice_pg = 0;
> +	sseu->has_subslice_pg = 0;
> +	sseu->has_eu_pg = 0;
> +}
> +
> +void intel_sseu_info_init(struct intel_gt *gt)
> +{
> +	struct drm_i915_private *i915 = gt->i915;
> +
> +	if (IS_HASWELL(i915))
> +		hsw_sseu_info_init(gt);
> +	else if (IS_CHERRYVIEW(i915))
> +		cherryview_sseu_info_init(gt);
> +	else if (IS_BROADWELL(i915))
> +		bdw_sseu_info_init(gt);
> +	else if (IS_GEN(i915, 9))
> +		gen9_sseu_info_init(gt);
> +	else if (IS_GEN(i915, 10))
> +		gen10_sseu_info_init(gt);
> +	else if (IS_GEN(i915, 11))
> +		gen11_sseu_info_init(gt);
> +	else if (INTEL_GEN(i915) >= 12)
> +		gen12_sseu_info_init(gt);
> +}
> +
>   u32 intel_sseu_make_rpcs(struct drm_i915_private *i915,
>   			 const struct intel_sseu *req_sseu)
>   {
> @@ -173,3 +715,48 @@ u32 intel_sseu_make_rpcs(struct drm_i915_private *i915,
>   
>   	return rpcs;
>   }
> +
> +void intel_sseu_dump(const struct sseu_dev_info *sseu, struct drm_printer *p)
> +{
> +	int s;
> +
> +	drm_printf(p, "slice total: %u, mask=%04x\n",
> +		   hweight8(sseu->slice_mask), sseu->slice_mask);
> +	drm_printf(p, "subslice total: %u\n", intel_sseu_subslice_total(sseu));
> +	for (s = 0; s < sseu->max_slices; s++) {
> +		drm_printf(p, "slice%d: %u subslices, mask=%08x\n",
> +			   s, intel_sseu_subslices_per_slice(sseu, s),
> +			   intel_sseu_get_subslices(sseu, s));
> +	}
> +	drm_printf(p, "EU total: %u\n", sseu->eu_total);
> +	drm_printf(p, "EU per subslice: %u\n", sseu->eu_per_subslice);
> +	drm_printf(p, "has slice power gating: %s\n",
> +		   yesno(sseu->has_slice_pg));
> +	drm_printf(p, "has subslice power gating: %s\n",
> +		   yesno(sseu->has_subslice_pg));
> +	drm_printf(p, "has EU power gating: %s\n", yesno(sseu->has_eu_pg));
> +}
> +
> +void intel_sseu_print_topology(const struct sseu_dev_info *sseu,
> +			       struct drm_printer *p)
> +{
> +	int s, ss;
> +
> +	if (sseu->max_slices == 0) {
> +		drm_printf(p, "Unavailable\n");
> +		return;
> +	}
> +
> +	for (s = 0; s < sseu->max_slices; s++) {
> +		drm_printf(p, "slice%d: %u subslice(s) (0x%08x):\n",
> +			   s, intel_sseu_subslices_per_slice(sseu, s),
> +			   intel_sseu_get_subslices(sseu, s));
> +
> +		for (ss = 0; ss < sseu->max_subslices; ss++) {
> +			u16 enabled_eus = sseu_get_eus(sseu, s, ss);
> +
> +			drm_printf(p, "\tsubslice%d: %u EUs (0x%hx)\n",
> +				   ss, hweight16(enabled_eus), enabled_eus);
> +		}
> +	}
> +}
> diff --git a/drivers/gpu/drm/i915/gt/intel_sseu.h b/drivers/gpu/drm/i915/gt/intel_sseu.h
> index d1d225204f09..f9c007f001e7 100644
> --- a/drivers/gpu/drm/i915/gt/intel_sseu.h
> +++ b/drivers/gpu/drm/i915/gt/intel_sseu.h
> @@ -13,6 +13,8 @@
>   #include "i915_gem.h"
>   
>   struct drm_i915_private;
> +struct intel_gt;
> +struct drm_printer;
>   
>   #define GEN_MAX_SLICES		(6) /* CNL upper bound */
>   #define GEN_MAX_SUBSLICES	(8) /* ICL upper bound */
> @@ -94,7 +96,13 @@ u32  intel_sseu_get_subslices(const struct sseu_dev_info *sseu, u8 slice);
>   void intel_sseu_set_subslices(struct sseu_dev_info *sseu, int slice,
>   			      u32 ss_mask);
>   
> +void intel_sseu_info_init(struct intel_gt *gt);
> +
>   u32 intel_sseu_make_rpcs(struct drm_i915_private *i915,
>   			 const struct intel_sseu *req_sseu);
>   
> +void intel_sseu_dump(const struct sseu_dev_info *sseu, struct drm_printer *p);
> +void intel_sseu_print_topology(const struct sseu_dev_info *sseu,
> +			       struct drm_printer *p);
> +
>   #endif /* __INTEL_SSEU_H__ */
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index cad1620d2a7e..c893a82c2d99 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -1323,7 +1323,7 @@ static int i915_rcs_topology(struct seq_file *m, void *unused)
>   	struct drm_i915_private *dev_priv = node_to_i915(m->private);
>   	struct drm_printer p = drm_seq_file_printer(m);
>   
> -	intel_device_info_print_topology(&RUNTIME_INFO(dev_priv)->sseu, &p);
> +	intel_sseu_print_topology(&RUNTIME_INFO(dev_priv)->sseu, &p);
>   
>   	return 0;
>   }
> diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
> index 9cb9aa39c33d..99b4a0261b13 100644
> --- a/drivers/gpu/drm/i915/i915_gpu_error.c
> +++ b/drivers/gpu/drm/i915/i915_gpu_error.c
> @@ -626,7 +626,7 @@ static void err_print_capabilities(struct drm_i915_error_state_buf *m,
>   
>   	intel_device_info_print_static(&error->device_info, &p);
>   	intel_device_info_print_runtime(&error->runtime_info, &p);
> -	intel_device_info_print_topology(&error->runtime_info.sseu, &p);
> +	intel_sseu_print_topology(&error->runtime_info.sseu, &p);
>   	intel_gt_info_print(&error->gt->info, &p);
>   	intel_driver_caps_print(&error->driver_caps, &p);
>   }
> diff --git a/drivers/gpu/drm/i915/intel_device_info.c b/drivers/gpu/drm/i915/intel_device_info.c
> index a362a66fce11..d8daf224cbd3 100644
> --- a/drivers/gpu/drm/i915/intel_device_info.c
> +++ b/drivers/gpu/drm/i915/intel_device_info.c
> @@ -29,6 +29,7 @@
>   #include "display/intel_de.h"
>   #include "intel_device_info.h"
>   #include "i915_drv.h"
> +#include "gt/intel_sseu.h"
>   
>   #define PLATFORM_NAME(x) [INTEL_##x] = #x
>   static const char * const platform_names[] = {
> @@ -111,581 +112,16 @@ void intel_device_info_print_static(const struct intel_device_info *info,
>   #undef PRINT_FLAG
>   }
>   
> -static void sseu_dump(const struct sseu_dev_info *sseu, struct drm_printer *p)
> -{
> -	int s;
> -
> -	drm_printf(p, "slice total: %u, mask=%04x\n",
> -		   hweight8(sseu->slice_mask), sseu->slice_mask);
> -	drm_printf(p, "subslice total: %u\n", intel_sseu_subslice_total(sseu));
> -	for (s = 0; s < sseu->max_slices; s++) {
> -		drm_printf(p, "slice%d: %u subslices, mask=%08x\n",
> -			   s, intel_sseu_subslices_per_slice(sseu, s),
> -			   intel_sseu_get_subslices(sseu, s));
> -	}
> -	drm_printf(p, "EU total: %u\n", sseu->eu_total);
> -	drm_printf(p, "EU per subslice: %u\n", sseu->eu_per_subslice);
> -	drm_printf(p, "has slice power gating: %s\n",
> -		   yesno(sseu->has_slice_pg));
> -	drm_printf(p, "has subslice power gating: %s\n",
> -		   yesno(sseu->has_subslice_pg));
> -	drm_printf(p, "has EU power gating: %s\n", yesno(sseu->has_eu_pg));
> -}
> -
>   void intel_device_info_print_runtime(const struct intel_runtime_info *info,
>   				     struct drm_printer *p)
>   {
> -	sseu_dump(&info->sseu, p);
> +	intel_sseu_dump(&info->sseu, p);
>   
>   	drm_printf(p, "rawclk rate: %u kHz\n", info->rawclk_freq);
>   	drm_printf(p, "CS timestamp frequency: %u Hz\n",
>   		   info->cs_timestamp_frequency_hz);
>   }
>   
> -static int sseu_eu_idx(const struct sseu_dev_info *sseu, int slice,
> -		       int subslice)
> -{
> -	int slice_stride = sseu->max_subslices * sseu->eu_stride;
> -
> -	return slice * slice_stride + subslice * sseu->eu_stride;
> -}
> -
> -static u16 sseu_get_eus(const struct sseu_dev_info *sseu, int slice,
> -			int subslice)
> -{
> -	int i, offset = sseu_eu_idx(sseu, slice, subslice);
> -	u16 eu_mask = 0;
> -
> -	for (i = 0; i < sseu->eu_stride; i++) {
> -		eu_mask |= ((u16)sseu->eu_mask[offset + i]) <<
> -			(i * BITS_PER_BYTE);
> -	}
> -
> -	return eu_mask;
> -}
> -
> -static void sseu_set_eus(struct sseu_dev_info *sseu, int slice, int subslice,
> -			 u16 eu_mask)
> -{
> -	int i, offset = sseu_eu_idx(sseu, slice, subslice);
> -
> -	for (i = 0; i < sseu->eu_stride; i++) {
> -		sseu->eu_mask[offset + i] =
> -			(eu_mask >> (BITS_PER_BYTE * i)) & 0xff;
> -	}
> -}
> -
> -void intel_device_info_print_topology(const struct sseu_dev_info *sseu,
> -				      struct drm_printer *p)
> -{
> -	int s, ss;
> -
> -	if (sseu->max_slices == 0) {
> -		drm_printf(p, "Unavailable\n");
> -		return;
> -	}
> -
> -	for (s = 0; s < sseu->max_slices; s++) {
> -		drm_printf(p, "slice%d: %u subslice(s) (0x%08x):\n",
> -			   s, intel_sseu_subslices_per_slice(sseu, s),
> -			   intel_sseu_get_subslices(sseu, s));
> -
> -		for (ss = 0; ss < sseu->max_subslices; ss++) {
> -			u16 enabled_eus = sseu_get_eus(sseu, s, ss);
> -
> -			drm_printf(p, "\tsubslice%d: %u EUs (0x%hx)\n",
> -				   ss, hweight16(enabled_eus), enabled_eus);
> -		}
> -	}
> -}
> -
> -static u16 compute_eu_total(const struct sseu_dev_info *sseu)
> -{
> -	u16 i, total = 0;
> -
> -	for (i = 0; i < ARRAY_SIZE(sseu->eu_mask); i++)
> -		total += hweight8(sseu->eu_mask[i]);
> -
> -	return total;
> -}
> -
> -static void gen11_compute_sseu_info(struct sseu_dev_info *sseu,
> -				    u8 s_en, u32 ss_en, u16 eu_en)
> -{
> -	int s, ss;
> -
> -	/* ss_en represents entire subslice mask across all slices */
> -	GEM_BUG_ON(sseu->max_slices * sseu->max_subslices >
> -		   sizeof(ss_en) * BITS_PER_BYTE);
> -
> -	for (s = 0; s < sseu->max_slices; s++) {
> -		if ((s_en & BIT(s)) == 0)
> -			continue;
> -
> -		sseu->slice_mask |= BIT(s);
> -
> -		intel_sseu_set_subslices(sseu, s, ss_en);
> -
> -		for (ss = 0; ss < sseu->max_subslices; ss++)
> -			if (intel_sseu_has_subslice(sseu, s, ss))
> -				sseu_set_eus(sseu, s, ss, eu_en);
> -	}
> -	sseu->eu_per_subslice = hweight16(eu_en);
> -	sseu->eu_total = compute_eu_total(sseu);
> -}
> -
> -static void gen12_sseu_info_init(struct drm_i915_private *dev_priv)
> -{
> -	struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu;
> -	struct intel_uncore *uncore = &dev_priv->uncore;
> -	u8 s_en;
> -	u32 dss_en;
> -	u16 eu_en = 0;
> -	u8 eu_en_fuse;
> -	int eu;
> -
> -	/*
> -	 * Gen12 has Dual-Subslices, which behave similarly to 2 gen11 SS.
> -	 * Instead of splitting these, provide userspace with an array
> -	 * of DSS to more closely represent the hardware resource.
> -	 */
> -	intel_sseu_set_info(sseu, 1, 6, 16);
> -
> -	s_en = intel_uncore_read(uncore, GEN11_GT_SLICE_ENABLE) &
> -	       GEN11_GT_S_ENA_MASK;
> -
> -	dss_en = intel_uncore_read(uncore, GEN12_GT_DSS_ENABLE);
> -
> -	/* one bit per pair of EUs */
> -	eu_en_fuse = ~(intel_uncore_read(uncore, GEN11_EU_DISABLE) &
> -		       GEN11_EU_DIS_MASK);
> -	for (eu = 0; eu < sseu->max_eus_per_subslice / 2; eu++)
> -		if (eu_en_fuse & BIT(eu))
> -			eu_en |= BIT(eu * 2) | BIT(eu * 2 + 1);
> -
> -	gen11_compute_sseu_info(sseu, s_en, dss_en, eu_en);
> -
> -	/* TGL only supports slice-level power gating */
> -	sseu->has_slice_pg = 1;
> -}
> -
> -static void gen11_sseu_info_init(struct drm_i915_private *dev_priv)
> -{
> -	struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu;
> -	struct intel_uncore *uncore = &dev_priv->uncore;
> -	u8 s_en;
> -	u32 ss_en;
> -	u8 eu_en;
> -
> -	if (IS_ELKHARTLAKE(dev_priv))
> -		intel_sseu_set_info(sseu, 1, 4, 8);
> -	else
> -		intel_sseu_set_info(sseu, 1, 8, 8);
> -
> -	s_en = intel_uncore_read(uncore, GEN11_GT_SLICE_ENABLE) &
> -	       GEN11_GT_S_ENA_MASK;
> -	ss_en = ~intel_uncore_read(uncore, GEN11_GT_SUBSLICE_DISABLE);
> -
> -	eu_en = ~(intel_uncore_read(uncore, GEN11_EU_DISABLE) &
> -		  GEN11_EU_DIS_MASK);
> -
> -	gen11_compute_sseu_info(sseu, s_en, ss_en, eu_en);
> -
> -	/* ICL has no power gating restrictions. */
> -	sseu->has_slice_pg = 1;
> -	sseu->has_subslice_pg = 1;
> -	sseu->has_eu_pg = 1;
> -}
> -
> -static void gen10_sseu_info_init(struct drm_i915_private *dev_priv)
> -{
> -	struct intel_uncore *uncore = &dev_priv->uncore;
> -	struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu;
> -	const u32 fuse2 = intel_uncore_read(uncore, GEN8_FUSE2);
> -	int s, ss;
> -	const int eu_mask = 0xff;
> -	u32 subslice_mask, eu_en;
> -
> -	intel_sseu_set_info(sseu, 6, 4, 8);
> -
> -	sseu->slice_mask = (fuse2 & GEN10_F2_S_ENA_MASK) >>
> -			    GEN10_F2_S_ENA_SHIFT;
> -
> -	/* Slice0 */
> -	eu_en = ~intel_uncore_read(uncore, GEN8_EU_DISABLE0);
> -	for (ss = 0; ss < sseu->max_subslices; ss++)
> -		sseu_set_eus(sseu, 0, ss, (eu_en >> (8 * ss)) & eu_mask);
> -	/* Slice1 */
> -	sseu_set_eus(sseu, 1, 0, (eu_en >> 24) & eu_mask);
> -	eu_en = ~intel_uncore_read(uncore, GEN8_EU_DISABLE1);
> -	sseu_set_eus(sseu, 1, 1, eu_en & eu_mask);
> -	/* Slice2 */
> -	sseu_set_eus(sseu, 2, 0, (eu_en >> 8) & eu_mask);
> -	sseu_set_eus(sseu, 2, 1, (eu_en >> 16) & eu_mask);
> -	/* Slice3 */
> -	sseu_set_eus(sseu, 3, 0, (eu_en >> 24) & eu_mask);
> -	eu_en = ~intel_uncore_read(uncore, GEN8_EU_DISABLE2);
> -	sseu_set_eus(sseu, 3, 1, eu_en & eu_mask);
> -	/* Slice4 */
> -	sseu_set_eus(sseu, 4, 0, (eu_en >> 8) & eu_mask);
> -	sseu_set_eus(sseu, 4, 1, (eu_en >> 16) & eu_mask);
> -	/* Slice5 */
> -	sseu_set_eus(sseu, 5, 0, (eu_en >> 24) & eu_mask);
> -	eu_en = ~intel_uncore_read(uncore, GEN10_EU_DISABLE3);
> -	sseu_set_eus(sseu, 5, 1, eu_en & eu_mask);
> -
> -	subslice_mask = (1 << 4) - 1;
> -	subslice_mask &= ~((fuse2 & GEN10_F2_SS_DIS_MASK) >>
> -			   GEN10_F2_SS_DIS_SHIFT);
> -
> -	for (s = 0; s < sseu->max_slices; s++) {
> -		u32 subslice_mask_with_eus = subslice_mask;
> -
> -		for (ss = 0; ss < sseu->max_subslices; ss++) {
> -			if (sseu_get_eus(sseu, s, ss) == 0)
> -				subslice_mask_with_eus &= ~BIT(ss);
> -		}
> -
> -		/*
> -		 * Slice0 can have up to 3 subslices, but there are only 2 in
> -		 * slice1/2.
> -		 */
> -		intel_sseu_set_subslices(sseu, s, s == 0 ?
> -						  subslice_mask_with_eus :
> -						  subslice_mask_with_eus & 0x3);
> -	}
> -
> -	sseu->eu_total = compute_eu_total(sseu);
> -
> -	/*
> -	 * CNL is expected to always have a uniform distribution
> -	 * of EU across subslices with the exception that any one
> -	 * EU in any one subslice may be fused off for die
> -	 * recovery.
> -	 */
> -	sseu->eu_per_subslice = intel_sseu_subslice_total(sseu) ?
> -				DIV_ROUND_UP(sseu->eu_total,
> -					     intel_sseu_subslice_total(sseu)) :
> -				0;
> -
> -	/* No restrictions on Power Gating */
> -	sseu->has_slice_pg = 1;
> -	sseu->has_subslice_pg = 1;
> -	sseu->has_eu_pg = 1;
> -}
> -
> -static void cherryview_sseu_info_init(struct drm_i915_private *dev_priv)
> -{
> -	struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu;
> -	u32 fuse;
> -	u8 subslice_mask = 0;
> -
> -	fuse = intel_uncore_read(&dev_priv->uncore, CHV_FUSE_GT);
> -
> -	sseu->slice_mask = BIT(0);
> -	intel_sseu_set_info(sseu, 1, 2, 8);
> -
> -	if (!(fuse & CHV_FGT_DISABLE_SS0)) {
> -		u8 disabled_mask =
> -			((fuse & CHV_FGT_EU_DIS_SS0_R0_MASK) >>
> -			 CHV_FGT_EU_DIS_SS0_R0_SHIFT) |
> -			(((fuse & CHV_FGT_EU_DIS_SS0_R1_MASK) >>
> -			  CHV_FGT_EU_DIS_SS0_R1_SHIFT) << 4);
> -
> -		subslice_mask |= BIT(0);
> -		sseu_set_eus(sseu, 0, 0, ~disabled_mask);
> -	}
> -
> -	if (!(fuse & CHV_FGT_DISABLE_SS1)) {
> -		u8 disabled_mask =
> -			((fuse & CHV_FGT_EU_DIS_SS1_R0_MASK) >>
> -			 CHV_FGT_EU_DIS_SS1_R0_SHIFT) |
> -			(((fuse & CHV_FGT_EU_DIS_SS1_R1_MASK) >>
> -			  CHV_FGT_EU_DIS_SS1_R1_SHIFT) << 4);
> -
> -		subslice_mask |= BIT(1);
> -		sseu_set_eus(sseu, 0, 1, ~disabled_mask);
> -	}
> -
> -	intel_sseu_set_subslices(sseu, 0, subslice_mask);
> -
> -	sseu->eu_total = compute_eu_total(sseu);
> -
> -	/*
> -	 * CHV expected to always have a uniform distribution of EU
> -	 * across subslices.
> -	*/
> -	sseu->eu_per_subslice = intel_sseu_subslice_total(sseu) ?
> -				sseu->eu_total /
> -					intel_sseu_subslice_total(sseu) :
> -				0;
> -	/*
> -	 * CHV supports subslice power gating on devices with more than
> -	 * one subslice, and supports EU power gating on devices with
> -	 * more than one EU pair per subslice.
> -	*/
> -	sseu->has_slice_pg = 0;
> -	sseu->has_subslice_pg = intel_sseu_subslice_total(sseu) > 1;
> -	sseu->has_eu_pg = (sseu->eu_per_subslice > 2);
> -}
> -
> -static void gen9_sseu_info_init(struct drm_i915_private *dev_priv)
> -{
> -	struct intel_device_info *info = mkwrite_device_info(dev_priv);
> -	struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu;
> -	struct intel_uncore *uncore = &dev_priv->uncore;
> -	int s, ss;
> -	u32 fuse2, eu_disable, subslice_mask;
> -	const u8 eu_mask = 0xff;
> -
> -	fuse2 = intel_uncore_read(uncore, GEN8_FUSE2);
> -	sseu->slice_mask = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;
> -
> -	/* BXT has a single slice and at most 3 subslices. */
> -	intel_sseu_set_info(sseu, IS_GEN9_LP(dev_priv) ? 1 : 3,
> -			    IS_GEN9_LP(dev_priv) ? 3 : 4, 8);
> -
> -	/*
> -	 * The subslice disable field is global, i.e. it applies
> -	 * to each of the enabled slices.
> -	*/
> -	subslice_mask = (1 << sseu->max_subslices) - 1;
> -	subslice_mask &= ~((fuse2 & GEN9_F2_SS_DIS_MASK) >>
> -			   GEN9_F2_SS_DIS_SHIFT);
> -
> -	/*
> -	 * Iterate through enabled slices and subslices to
> -	 * count the total enabled EU.
> -	*/
> -	for (s = 0; s < sseu->max_slices; s++) {
> -		if (!(sseu->slice_mask & BIT(s)))
> -			/* skip disabled slice */
> -			continue;
> -
> -		intel_sseu_set_subslices(sseu, s, subslice_mask);
> -
> -		eu_disable = intel_uncore_read(uncore, GEN9_EU_DISABLE(s));
> -		for (ss = 0; ss < sseu->max_subslices; ss++) {
> -			int eu_per_ss;
> -			u8 eu_disabled_mask;
> -
> -			if (!intel_sseu_has_subslice(sseu, s, ss))
> -				/* skip disabled subslice */
> -				continue;
> -
> -			eu_disabled_mask = (eu_disable >> (ss * 8)) & eu_mask;
> -
> -			sseu_set_eus(sseu, s, ss, ~eu_disabled_mask);
> -
> -			eu_per_ss = sseu->max_eus_per_subslice -
> -				hweight8(eu_disabled_mask);
> -
> -			/*
> -			 * Record which subslice(s) has(have) 7 EUs. we
> -			 * can tune the hash used to spread work among
> -			 * subslices if they are unbalanced.
> -			 */
> -			if (eu_per_ss == 7)
> -				sseu->subslice_7eu[s] |= BIT(ss);
> -		}
> -	}
> -
> -	sseu->eu_total = compute_eu_total(sseu);
> -
> -	/*
> -	 * SKL is expected to always have a uniform distribution
> -	 * of EU across subslices with the exception that any one
> -	 * EU in any one subslice may be fused off for die
> -	 * recovery. BXT is expected to be perfectly uniform in EU
> -	 * distribution.
> -	*/
> -	sseu->eu_per_subslice = intel_sseu_subslice_total(sseu) ?
> -				DIV_ROUND_UP(sseu->eu_total,
> -					     intel_sseu_subslice_total(sseu)) :
> -				0;
> -	/*
> -	 * SKL+ supports slice power gating on devices with more than
> -	 * one slice, and supports EU power gating on devices with
> -	 * more than one EU pair per subslice. BXT+ supports subslice
> -	 * power gating on devices with more than one subslice, and
> -	 * supports EU power gating on devices with more than one EU
> -	 * pair per subslice.
> -	*/
> -	sseu->has_slice_pg =
> -		!IS_GEN9_LP(dev_priv) && hweight8(sseu->slice_mask) > 1;
> -	sseu->has_subslice_pg =
> -		IS_GEN9_LP(dev_priv) && intel_sseu_subslice_total(sseu) > 1;
> -	sseu->has_eu_pg = sseu->eu_per_subslice > 2;
> -
> -	if (IS_GEN9_LP(dev_priv)) {
> -#define IS_SS_DISABLED(ss)	(!(sseu->subslice_mask[0] & BIT(ss)))
> -		info->has_pooled_eu = hweight8(sseu->subslice_mask[0]) == 3;
> -
> -		sseu->min_eu_in_pool = 0;
> -		if (info->has_pooled_eu) {
> -			if (IS_SS_DISABLED(2) || IS_SS_DISABLED(0))
> -				sseu->min_eu_in_pool = 3;
> -			else if (IS_SS_DISABLED(1))
> -				sseu->min_eu_in_pool = 6;
> -			else
> -				sseu->min_eu_in_pool = 9;
> -		}
> -#undef IS_SS_DISABLED
> -	}
> -}
> -
> -static void bdw_sseu_info_init(struct drm_i915_private *dev_priv)
> -{
> -	struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu;
> -	struct intel_uncore *uncore = &dev_priv->uncore;
> -	int s, ss;
> -	u32 fuse2, subslice_mask, eu_disable[3]; /* s_max */
> -	u32 eu_disable0, eu_disable1, eu_disable2;
> -
> -	fuse2 = intel_uncore_read(uncore, GEN8_FUSE2);
> -	sseu->slice_mask = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;
> -	intel_sseu_set_info(sseu, 3, 3, 8);
> -
> -	/*
> -	 * The subslice disable field is global, i.e. it applies
> -	 * to each of the enabled slices.
> -	 */
> -	subslice_mask = GENMASK(sseu->max_subslices - 1, 0);
> -	subslice_mask &= ~((fuse2 & GEN8_F2_SS_DIS_MASK) >>
> -			   GEN8_F2_SS_DIS_SHIFT);
> -	eu_disable0 = intel_uncore_read(uncore, GEN8_EU_DISABLE0);
> -	eu_disable1 = intel_uncore_read(uncore, GEN8_EU_DISABLE1);
> -	eu_disable2 = intel_uncore_read(uncore, GEN8_EU_DISABLE2);
> -	eu_disable[0] = eu_disable0 & GEN8_EU_DIS0_S0_MASK;
> -	eu_disable[1] = (eu_disable0 >> GEN8_EU_DIS0_S1_SHIFT) |
> -			((eu_disable1 & GEN8_EU_DIS1_S1_MASK) <<
> -			 (32 - GEN8_EU_DIS0_S1_SHIFT));
> -	eu_disable[2] = (eu_disable1 >> GEN8_EU_DIS1_S2_SHIFT) |
> -			((eu_disable2 & GEN8_EU_DIS2_S2_MASK) <<
> -			 (32 - GEN8_EU_DIS1_S2_SHIFT));
> -
> -	/*
> -	 * Iterate through enabled slices and subslices to
> -	 * count the total enabled EU.
> -	 */
> -	for (s = 0; s < sseu->max_slices; s++) {
> -		if (!(sseu->slice_mask & BIT(s)))
> -			/* skip disabled slice */
> -			continue;
> -
> -		intel_sseu_set_subslices(sseu, s, subslice_mask);
> -
> -		for (ss = 0; ss < sseu->max_subslices; ss++) {
> -			u8 eu_disabled_mask;
> -			u32 n_disabled;
> -
> -			if (!intel_sseu_has_subslice(sseu, s, ss))
> -				/* skip disabled subslice */
> -				continue;
> -
> -			eu_disabled_mask =
> -				eu_disable[s] >> (ss * sseu->max_eus_per_subslice);
> -
> -			sseu_set_eus(sseu, s, ss, ~eu_disabled_mask);
> -
> -			n_disabled = hweight8(eu_disabled_mask);
> -
> -			/*
> -			 * Record which subslices have 7 EUs.
> -			 */
> -			if (sseu->max_eus_per_subslice - n_disabled == 7)
> -				sseu->subslice_7eu[s] |= 1 << ss;
> -		}
> -	}
> -
> -	sseu->eu_total = compute_eu_total(sseu);
> -
> -	/*
> -	 * BDW is expected to always have a uniform distribution of EU across
> -	 * subslices with the exception that any one EU in any one subslice may
> -	 * be fused off for die recovery.
> -	 */
> -	sseu->eu_per_subslice = intel_sseu_subslice_total(sseu) ?
> -				DIV_ROUND_UP(sseu->eu_total,
> -					     intel_sseu_subslice_total(sseu)) :
> -				0;
> -
> -	/*
> -	 * BDW supports slice power gating on devices with more than
> -	 * one slice.
> -	 */
> -	sseu->has_slice_pg = hweight8(sseu->slice_mask) > 1;
> -	sseu->has_subslice_pg = 0;
> -	sseu->has_eu_pg = 0;
> -}
> -
> -static void hsw_sseu_info_init(struct drm_i915_private *dev_priv)
> -{
> -	struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu;
> -	u32 fuse1;
> -	u8 subslice_mask = 0;
> -	int s, ss;
> -
> -	/*
> -	 * There isn't a register to tell us how many slices/subslices. We
> -	 * work off the PCI-ids here.
> -	 */
> -	switch (INTEL_INFO(dev_priv)->gt) {
> -	default:
> -		MISSING_CASE(INTEL_INFO(dev_priv)->gt);
> -		/* fall through */
> -	case 1:
> -		sseu->slice_mask = BIT(0);
> -		subslice_mask = BIT(0);
> -		break;
> -	case 2:
> -		sseu->slice_mask = BIT(0);
> -		subslice_mask = BIT(0) | BIT(1);
> -		break;
> -	case 3:
> -		sseu->slice_mask = BIT(0) | BIT(1);
> -		subslice_mask = BIT(0) | BIT(1);
> -		break;
> -	}
> -
> -	fuse1 = intel_uncore_read(&dev_priv->uncore, HSW_PAVP_FUSE1);
> -	switch ((fuse1 & HSW_F1_EU_DIS_MASK) >> HSW_F1_EU_DIS_SHIFT) {
> -	default:
> -		MISSING_CASE((fuse1 & HSW_F1_EU_DIS_MASK) >>
> -			     HSW_F1_EU_DIS_SHIFT);
> -		/* fall through */
> -	case HSW_F1_EU_DIS_10EUS:
> -		sseu->eu_per_subslice = 10;
> -		break;
> -	case HSW_F1_EU_DIS_8EUS:
> -		sseu->eu_per_subslice = 8;
> -		break;
> -	case HSW_F1_EU_DIS_6EUS:
> -		sseu->eu_per_subslice = 6;
> -		break;
> -	}
> -
> -	intel_sseu_set_info(sseu, hweight8(sseu->slice_mask),
> -			    hweight8(subslice_mask),
> -			    sseu->eu_per_subslice);
> -
> -	for (s = 0; s < sseu->max_slices; s++) {
> -		intel_sseu_set_subslices(sseu, s, subslice_mask);
> -
> -		for (ss = 0; ss < sseu->max_subslices; ss++) {
> -			sseu_set_eus(sseu, s, ss,
> -				     (1UL << sseu->eu_per_subslice) - 1);
> -		}
> -	}
> -
> -	sseu->eu_total = compute_eu_total(sseu);
> -
> -	/* No powergating for you. */
> -	sseu->has_slice_pg = 0;
> -	sseu->has_subslice_pg = 0;
> -	sseu->has_eu_pg = 0;
> -}
> -
>   static u32 read_reference_ts_freq(struct drm_i915_private *dev_priv)
>   {
>   	u32 ts_override = intel_uncore_read(&dev_priv->uncore,
> @@ -1042,22 +478,6 @@ void intel_device_info_runtime_init(struct drm_i915_private *dev_priv)
>   			info->display.has_dsc = 0;
>   	}
>   
> -	/* Initialize slice/subslice/EU info */
> -	if (IS_HASWELL(dev_priv))
> -		hsw_sseu_info_init(dev_priv);
> -	else if (IS_CHERRYVIEW(dev_priv))
> -		cherryview_sseu_info_init(dev_priv);
> -	else if (IS_BROADWELL(dev_priv))
> -		bdw_sseu_info_init(dev_priv);
> -	else if (IS_GEN(dev_priv, 9))
> -		gen9_sseu_info_init(dev_priv);
> -	else if (IS_GEN(dev_priv, 10))
> -		gen10_sseu_info_init(dev_priv);
> -	else if (IS_GEN(dev_priv, 11))
> -		gen11_sseu_info_init(dev_priv);
> -	else if (INTEL_GEN(dev_priv) >= 12)
> -		gen12_sseu_info_init(dev_priv);
> -
>   	if (IS_GEN(dev_priv, 6) && intel_vtd_active()) {
>   		drm_info(&dev_priv->drm,
>   			 "Disabling ppGTT for VT-d support\n");
> diff --git a/drivers/gpu/drm/i915/intel_device_info.h b/drivers/gpu/drm/i915/intel_device_info.h
> index f03ed95af190..ce2ccee9b49b 100644
> --- a/drivers/gpu/drm/i915/intel_device_info.h
> +++ b/drivers/gpu/drm/i915/intel_device_info.h
> @@ -242,8 +242,6 @@ void intel_device_info_print_static(const struct intel_device_info *info,
>   				    struct drm_printer *p);
>   void intel_device_info_print_runtime(const struct intel_runtime_info *info,
>   				     struct drm_printer *p);
> -void intel_device_info_print_topology(const struct sseu_dev_info *sseu,
> -				      struct drm_printer *p);
>   
>   void intel_driver_caps_print(const struct intel_driver_caps *caps,
>   			     struct drm_printer *p);
> 

I tried to check side by side as much as I could. Occasionaly cut&paste 
of wonky formatting strangely re-assured me move was good.

Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

Regards,

Tvrtko

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

  reply	other threads:[~2020-06-26 15:01 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-06-25 23:42 [Intel-gfx] [PATCH 0/7] Move some device capabilities under intel_gt Daniele Ceraolo Spurio
2020-06-25 23:42 ` [Intel-gfx] [PATCH 1/7] drm/i915: Convert device_info to uncore/de_read Daniele Ceraolo Spurio
2020-06-26 14:18   ` Tvrtko Ursulin
2020-06-25 23:42 ` [Intel-gfx] [PATCH 2/7] drm/i915: Use the gt in HAS_ENGINE Daniele Ceraolo Spurio
2020-06-26 14:20   ` Tvrtko Ursulin
2020-06-26 14:35   ` Chris Wilson
2020-06-26 17:45     ` Daniele Ceraolo Spurio
2020-06-26 18:03       ` Chris Wilson
2020-06-25 23:42 ` [Intel-gfx] [PATCH 3/7] drm/i915: Move engine-related mmio init to engines_init_mmio Daniele Ceraolo Spurio
2020-06-26 14:38   ` Tvrtko Ursulin
2020-06-26 14:38   ` Chris Wilson
2020-06-26 14:46     ` Daniele Ceraolo Spurio
2020-06-26 14:51       ` Chris Wilson
2020-06-25 23:42 ` [Intel-gfx] [PATCH 4/7] drm/i915: Move the engine mask to intel_gt_info Daniele Ceraolo Spurio
2020-06-26 14:45   ` Tvrtko Ursulin
2020-06-26 16:44     ` Daniele Ceraolo Spurio
2020-06-26 16:50       ` Chris Wilson
2020-06-25 23:42 ` [Intel-gfx] [PATCH 5/7] drm/i915: Introduce gt_init_mmio Daniele Ceraolo Spurio
2020-06-26 14:46   ` Tvrtko Ursulin
2020-06-25 23:42 ` [Intel-gfx] [PATCH 6/7] drm/i915/sseu: Move sseu detection and dump to intel_sseu Daniele Ceraolo Spurio
2020-06-26 15:00   ` Tvrtko Ursulin [this message]
2020-06-25 23:42 ` [Intel-gfx] [PATCH 7/7] drm/i915/sseu: Move sseu_info under gt_info Daniele Ceraolo Spurio
2020-06-26 15:22   ` Tvrtko Ursulin
2020-06-26 16:49     ` Daniele Ceraolo Spurio
2020-06-27  8:13 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for Move some device capabilities under intel_gt Patchwork
2020-06-27  8:38 ` [Intel-gfx] ✗ Fi.CI.BAT: failure " Patchwork

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=841291ae-40d8-c430-dbc8-6b16f7fbc713@linux.intel.com \
    --to=tvrtko.ursulin@linux.intel.com \
    --cc=daniele.ceraolospurio@intel.com \
    --cc=intel-gfx@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.