brintos

brintos / linux-shallow public Read only

0
0
Text · 24.1 KiB · c8fadf5 Raw
896 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright © 2019 Intel Corporation4 */5 6#include <linux/string_helpers.h>7 8#include "i915_drv.h"9#include "i915_perf_types.h"10#include "intel_engine_regs.h"11#include "intel_gt_regs.h"12#include "intel_sseu.h"13 14void intel_sseu_set_info(struct sseu_dev_info *sseu, u8 max_slices,15			 u8 max_subslices, u8 max_eus_per_subslice)16{17	sseu->max_slices = max_slices;18	sseu->max_subslices = max_subslices;19	sseu->max_eus_per_subslice = max_eus_per_subslice;20}21 22unsigned int23intel_sseu_subslice_total(const struct sseu_dev_info *sseu)24{25	unsigned int i, total = 0;26 27	if (sseu->has_xehp_dss)28		return bitmap_weight(sseu->subslice_mask.xehp,29				     XEHP_BITMAP_BITS(sseu->subslice_mask));30 31	for (i = 0; i < ARRAY_SIZE(sseu->subslice_mask.hsw); i++)32		total += hweight8(sseu->subslice_mask.hsw[i]);33 34	return total;35}36 37unsigned int38intel_sseu_get_hsw_subslices(const struct sseu_dev_info *sseu, u8 slice)39{40	WARN_ON(sseu->has_xehp_dss);41	if (WARN_ON(slice >= sseu->max_slices))42		return 0;43 44	return sseu->subslice_mask.hsw[slice];45}46 47static u16 sseu_get_eus(const struct sseu_dev_info *sseu, int slice,48			int subslice)49{50	if (sseu->has_xehp_dss) {51		WARN_ON(slice > 0);52		return sseu->eu_mask.xehp[subslice];53	} else {54		return sseu->eu_mask.hsw[slice][subslice];55	}56}57 58static void sseu_set_eus(struct sseu_dev_info *sseu, int slice, int subslice,59			 u16 eu_mask)60{61	GEM_WARN_ON(eu_mask && __fls(eu_mask) >= sseu->max_eus_per_subslice);62	if (sseu->has_xehp_dss) {63		GEM_WARN_ON(slice > 0);64		sseu->eu_mask.xehp[subslice] = eu_mask;65	} else {66		sseu->eu_mask.hsw[slice][subslice] = eu_mask;67	}68}69 70static u16 compute_eu_total(const struct sseu_dev_info *sseu)71{72	int s, ss, total = 0;73 74	for (s = 0; s < sseu->max_slices; s++)75		for (ss = 0; ss < sseu->max_subslices; ss++)76			if (sseu->has_xehp_dss)77				total += hweight16(sseu->eu_mask.xehp[ss]);78			else79				total += hweight16(sseu->eu_mask.hsw[s][ss]);80 81	return total;82}83 84/**85 * intel_sseu_copy_eumask_to_user - Copy EU mask into a userspace buffer86 * @to: Pointer to userspace buffer to copy to87 * @sseu: SSEU structure containing EU mask to copy88 *89 * Copies the EU mask to a userspace buffer in the format expected by90 * the query ioctl's topology queries.91 *92 * Returns the result of the copy_to_user() operation.93 */94int intel_sseu_copy_eumask_to_user(void __user *to,95				   const struct sseu_dev_info *sseu)96{97	u8 eu_mask[GEN_SS_MASK_SIZE * GEN_MAX_EU_STRIDE] = {};98	int eu_stride = GEN_SSEU_STRIDE(sseu->max_eus_per_subslice);99	int len = sseu->max_slices * sseu->max_subslices * eu_stride;100	int s, ss, i;101 102	for (s = 0; s < sseu->max_slices; s++) {103		for (ss = 0; ss < sseu->max_subslices; ss++) {104			int uapi_offset =105				s * sseu->max_subslices * eu_stride +106				ss * eu_stride;107			u16 mask = sseu_get_eus(sseu, s, ss);108 109			for (i = 0; i < eu_stride; i++)110				eu_mask[uapi_offset + i] =111					(mask >> (BITS_PER_BYTE * i)) & 0xff;112		}113	}114 115	return copy_to_user(to, eu_mask, len);116}117 118/**119 * intel_sseu_copy_ssmask_to_user - Copy subslice mask into a userspace buffer120 * @to: Pointer to userspace buffer to copy to121 * @sseu: SSEU structure containing subslice mask to copy122 *123 * Copies the subslice mask to a userspace buffer in the format expected by124 * the query ioctl's topology queries.125 *126 * Returns the result of the copy_to_user() operation.127 */128int intel_sseu_copy_ssmask_to_user(void __user *to,129				   const struct sseu_dev_info *sseu)130{131	u8 ss_mask[GEN_SS_MASK_SIZE] = {};132	int ss_stride = GEN_SSEU_STRIDE(sseu->max_subslices);133	int len = sseu->max_slices * ss_stride;134	int s, ss, i;135 136	for (s = 0; s < sseu->max_slices; s++) {137		for (ss = 0; ss < sseu->max_subslices; ss++) {138			i = s * ss_stride * BITS_PER_BYTE + ss;139 140			if (!intel_sseu_has_subslice(sseu, s, ss))141				continue;142 143			ss_mask[i / BITS_PER_BYTE] |= BIT(i % BITS_PER_BYTE);144		}145	}146 147	return copy_to_user(to, ss_mask, len);148}149 150static void gen11_compute_sseu_info(struct sseu_dev_info *sseu,151				    u32 ss_en, u16 eu_en)152{153	u32 valid_ss_mask = GENMASK(sseu->max_subslices - 1, 0);154	int ss;155 156	sseu->slice_mask |= BIT(0);157	sseu->subslice_mask.hsw[0] = ss_en & valid_ss_mask;158 159	for (ss = 0; ss < sseu->max_subslices; ss++)160		if (intel_sseu_has_subslice(sseu, 0, ss))161			sseu_set_eus(sseu, 0, ss, eu_en);162 163	sseu->eu_per_subslice = hweight16(eu_en);164	sseu->eu_total = compute_eu_total(sseu);165}166 167static void xehp_compute_sseu_info(struct sseu_dev_info *sseu,168				   u16 eu_en)169{170	int ss;171 172	sseu->slice_mask |= BIT(0);173 174	bitmap_or(sseu->subslice_mask.xehp,175		  sseu->compute_subslice_mask.xehp,176		  sseu->geometry_subslice_mask.xehp,177		  XEHP_BITMAP_BITS(sseu->subslice_mask));178 179	for (ss = 0; ss < sseu->max_subslices; ss++)180		if (intel_sseu_has_subslice(sseu, 0, ss))181			sseu_set_eus(sseu, 0, ss, eu_en);182 183	sseu->eu_per_subslice = hweight16(eu_en);184	sseu->eu_total = compute_eu_total(sseu);185}186 187static void188xehp_load_dss_mask(struct intel_uncore *uncore,189		   intel_sseu_ss_mask_t *ssmask,190		   int numregs,191		   ...)192{193	va_list argp;194	u32 fuse_val[I915_MAX_SS_FUSE_REGS] = {};195	int i;196 197	if (WARN_ON(numregs > I915_MAX_SS_FUSE_REGS))198		numregs = I915_MAX_SS_FUSE_REGS;199 200	va_start(argp, numregs);201	for (i = 0; i < numregs; i++)202		fuse_val[i] = intel_uncore_read(uncore, va_arg(argp, i915_reg_t));203	va_end(argp);204 205	bitmap_from_arr32(ssmask->xehp, fuse_val, numregs * 32);206}207 208static void xehp_sseu_info_init(struct intel_gt *gt)209{210	struct sseu_dev_info *sseu = &gt->info.sseu;211	struct intel_uncore *uncore = gt->uncore;212	u16 eu_en = 0;213	u8 eu_en_fuse;214	int num_compute_regs, num_geometry_regs;215	int eu;216 217	num_geometry_regs = 1;218	num_compute_regs = 1;219 220	/*221	 * The concept of slice has been removed in Xe_HP.  To be compatible222	 * with prior generations, assume a single slice across the entire223	 * device. Then calculate out the DSS for each workload type within224	 * that software slice.225	 */226	intel_sseu_set_info(sseu, 1,227			    32 * max(num_geometry_regs, num_compute_regs),228			    HAS_ONE_EU_PER_FUSE_BIT(gt->i915) ? 8 : 16);229	sseu->has_xehp_dss = 1;230 231	xehp_load_dss_mask(uncore, &sseu->geometry_subslice_mask,232			   num_geometry_regs,233			   GEN12_GT_GEOMETRY_DSS_ENABLE);234	xehp_load_dss_mask(uncore, &sseu->compute_subslice_mask,235			   num_compute_regs,236			   GEN12_GT_COMPUTE_DSS_ENABLE,237			   XEHPC_GT_COMPUTE_DSS_ENABLE_EXT);238 239	eu_en_fuse = intel_uncore_read(uncore, XEHP_EU_ENABLE) & XEHP_EU_ENA_MASK;240 241	if (HAS_ONE_EU_PER_FUSE_BIT(gt->i915))242		eu_en = eu_en_fuse;243	else244		for (eu = 0; eu < sseu->max_eus_per_subslice / 2; eu++)245			if (eu_en_fuse & BIT(eu))246				eu_en |= BIT(eu * 2) | BIT(eu * 2 + 1);247 248	xehp_compute_sseu_info(sseu, eu_en);249}250 251static void gen12_sseu_info_init(struct intel_gt *gt)252{253	struct sseu_dev_info *sseu = &gt->info.sseu;254	struct intel_uncore *uncore = gt->uncore;255	u32 g_dss_en;256	u16 eu_en = 0;257	u8 eu_en_fuse;258	u8 s_en;259	int eu;260 261	/*262	 * Gen12 has Dual-Subslices, which behave similarly to 2 gen11 SS.263	 * Instead of splitting these, provide userspace with an array264	 * of DSS to more closely represent the hardware resource.265	 */266	intel_sseu_set_info(sseu, 1, 6, 16);267 268	/*269	 * Although gen12 architecture supported multiple slices, TGL, RKL,270	 * DG1, and ADL only had a single slice.271	 */272	s_en = intel_uncore_read(uncore, GEN11_GT_SLICE_ENABLE) &273		GEN11_GT_S_ENA_MASK;274	drm_WARN_ON(&gt->i915->drm, s_en != 0x1);275 276	g_dss_en = intel_uncore_read(uncore, GEN12_GT_GEOMETRY_DSS_ENABLE);277 278	/* one bit per pair of EUs */279	eu_en_fuse = ~(intel_uncore_read(uncore, GEN11_EU_DISABLE) &280		       GEN11_EU_DIS_MASK);281 282	for (eu = 0; eu < sseu->max_eus_per_subslice / 2; eu++)283		if (eu_en_fuse & BIT(eu))284			eu_en |= BIT(eu * 2) | BIT(eu * 2 + 1);285 286	gen11_compute_sseu_info(sseu, g_dss_en, eu_en);287 288	/* TGL only supports slice-level power gating */289	sseu->has_slice_pg = 1;290}291 292static void gen11_sseu_info_init(struct intel_gt *gt)293{294	struct sseu_dev_info *sseu = &gt->info.sseu;295	struct intel_uncore *uncore = gt->uncore;296	u32 ss_en;297	u8 eu_en;298	u8 s_en;299 300	if (IS_JASPERLAKE(gt->i915) || IS_ELKHARTLAKE(gt->i915))301		intel_sseu_set_info(sseu, 1, 4, 8);302	else303		intel_sseu_set_info(sseu, 1, 8, 8);304 305	/*306	 * Although gen11 architecture supported multiple slices, ICL and307	 * EHL/JSL only had a single slice in practice.308	 */309	s_en = intel_uncore_read(uncore, GEN11_GT_SLICE_ENABLE) &310		GEN11_GT_S_ENA_MASK;311	drm_WARN_ON(&gt->i915->drm, s_en != 0x1);312 313	ss_en = ~intel_uncore_read(uncore, GEN11_GT_SUBSLICE_DISABLE);314 315	eu_en = ~(intel_uncore_read(uncore, GEN11_EU_DISABLE) &316		  GEN11_EU_DIS_MASK);317 318	gen11_compute_sseu_info(sseu, ss_en, eu_en);319 320	/* ICL has no power gating restrictions. */321	sseu->has_slice_pg = 1;322	sseu->has_subslice_pg = 1;323	sseu->has_eu_pg = 1;324}325 326static void cherryview_sseu_info_init(struct intel_gt *gt)327{328	struct sseu_dev_info *sseu = &gt->info.sseu;329	u32 fuse;330 331	fuse = intel_uncore_read(gt->uncore, CHV_FUSE_GT);332 333	sseu->slice_mask = BIT(0);334	intel_sseu_set_info(sseu, 1, 2, 8);335 336	if (!(fuse & CHV_FGT_DISABLE_SS0)) {337		u8 disabled_mask =338			((fuse & CHV_FGT_EU_DIS_SS0_R0_MASK) >>339			 CHV_FGT_EU_DIS_SS0_R0_SHIFT) |340			(((fuse & CHV_FGT_EU_DIS_SS0_R1_MASK) >>341			  CHV_FGT_EU_DIS_SS0_R1_SHIFT) << 4);342 343		sseu->subslice_mask.hsw[0] |= BIT(0);344		sseu_set_eus(sseu, 0, 0, ~disabled_mask & 0xFF);345	}346 347	if (!(fuse & CHV_FGT_DISABLE_SS1)) {348		u8 disabled_mask =349			((fuse & CHV_FGT_EU_DIS_SS1_R0_MASK) >>350			 CHV_FGT_EU_DIS_SS1_R0_SHIFT) |351			(((fuse & CHV_FGT_EU_DIS_SS1_R1_MASK) >>352			  CHV_FGT_EU_DIS_SS1_R1_SHIFT) << 4);353 354		sseu->subslice_mask.hsw[0] |= BIT(1);355		sseu_set_eus(sseu, 0, 1, ~disabled_mask & 0xFF);356	}357 358	sseu->eu_total = compute_eu_total(sseu);359 360	/*361	 * CHV expected to always have a uniform distribution of EU362	 * across subslices.363	 */364	sseu->eu_per_subslice = intel_sseu_subslice_total(sseu) ?365		sseu->eu_total /366		intel_sseu_subslice_total(sseu) :367		0;368	/*369	 * CHV supports subslice power gating on devices with more than370	 * one subslice, and supports EU power gating on devices with371	 * more than one EU pair per subslice.372	 */373	sseu->has_slice_pg = 0;374	sseu->has_subslice_pg = intel_sseu_subslice_total(sseu) > 1;375	sseu->has_eu_pg = (sseu->eu_per_subslice > 2);376}377 378static void gen9_sseu_info_init(struct intel_gt *gt)379{380	struct drm_i915_private *i915 = gt->i915;381	struct sseu_dev_info *sseu = &gt->info.sseu;382	struct intel_uncore *uncore = gt->uncore;383	u32 fuse2, eu_disable, subslice_mask;384	const u8 eu_mask = 0xff;385	int s, ss;386 387	fuse2 = intel_uncore_read(uncore, GEN8_FUSE2);388	sseu->slice_mask = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;389 390	/* BXT has a single slice and at most 3 subslices. */391	intel_sseu_set_info(sseu, IS_GEN9_LP(i915) ? 1 : 3,392			    IS_GEN9_LP(i915) ? 3 : 4, 8);393 394	/*395	 * The subslice disable field is global, i.e. it applies396	 * to each of the enabled slices.397	 */398	subslice_mask = (1 << sseu->max_subslices) - 1;399	subslice_mask &= ~((fuse2 & GEN9_F2_SS_DIS_MASK) >>400			   GEN9_F2_SS_DIS_SHIFT);401 402	/*403	 * Iterate through enabled slices and subslices to404	 * count the total enabled EU.405	 */406	for (s = 0; s < sseu->max_slices; s++) {407		if (!(sseu->slice_mask & BIT(s)))408			/* skip disabled slice */409			continue;410 411		sseu->subslice_mask.hsw[s] = subslice_mask;412 413		eu_disable = intel_uncore_read(uncore, GEN9_EU_DISABLE(s));414		for (ss = 0; ss < sseu->max_subslices; ss++) {415			int eu_per_ss;416			u8 eu_disabled_mask;417 418			if (!intel_sseu_has_subslice(sseu, s, ss))419				/* skip disabled subslice */420				continue;421 422			eu_disabled_mask = (eu_disable >> (ss * 8)) & eu_mask;423 424			sseu_set_eus(sseu, s, ss, ~eu_disabled_mask & eu_mask);425 426			eu_per_ss = sseu->max_eus_per_subslice -427				hweight8(eu_disabled_mask);428 429			/*430			 * Record which subslice(s) has(have) 7 EUs. we431			 * can tune the hash used to spread work among432			 * subslices if they are unbalanced.433			 */434			if (eu_per_ss == 7)435				sseu->subslice_7eu[s] |= BIT(ss);436		}437	}438 439	sseu->eu_total = compute_eu_total(sseu);440 441	/*442	 * SKL is expected to always have a uniform distribution443	 * of EU across subslices with the exception that any one444	 * EU in any one subslice may be fused off for die445	 * recovery. BXT is expected to be perfectly uniform in EU446	 * distribution.447	 */448	sseu->eu_per_subslice =449		intel_sseu_subslice_total(sseu) ?450		DIV_ROUND_UP(sseu->eu_total, intel_sseu_subslice_total(sseu)) :451		0;452 453	/*454	 * SKL+ supports slice power gating on devices with more than455	 * one slice, and supports EU power gating on devices with456	 * more than one EU pair per subslice. BXT+ supports subslice457	 * power gating on devices with more than one subslice, and458	 * supports EU power gating on devices with more than one EU459	 * pair per subslice.460	 */461	sseu->has_slice_pg =462		!IS_GEN9_LP(i915) && hweight8(sseu->slice_mask) > 1;463	sseu->has_subslice_pg =464		IS_GEN9_LP(i915) && intel_sseu_subslice_total(sseu) > 1;465	sseu->has_eu_pg = sseu->eu_per_subslice > 2;466 467	if (IS_GEN9_LP(i915)) {468#define IS_SS_DISABLED(ss)	(!(sseu->subslice_mask.hsw[0] & BIT(ss)))469		RUNTIME_INFO(i915)->has_pooled_eu = hweight8(sseu->subslice_mask.hsw[0]) == 3;470 471		sseu->min_eu_in_pool = 0;472		if (HAS_POOLED_EU(i915)) {473			if (IS_SS_DISABLED(2) || IS_SS_DISABLED(0))474				sseu->min_eu_in_pool = 3;475			else if (IS_SS_DISABLED(1))476				sseu->min_eu_in_pool = 6;477			else478				sseu->min_eu_in_pool = 9;479		}480#undef IS_SS_DISABLED481	}482}483 484static void bdw_sseu_info_init(struct intel_gt *gt)485{486	struct sseu_dev_info *sseu = &gt->info.sseu;487	struct intel_uncore *uncore = gt->uncore;488	int s, ss;489	u32 fuse2, subslice_mask, eu_disable[3]; /* s_max */490	u32 eu_disable0, eu_disable1, eu_disable2;491 492	fuse2 = intel_uncore_read(uncore, GEN8_FUSE2);493	sseu->slice_mask = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;494	intel_sseu_set_info(sseu, 3, 3, 8);495 496	/*497	 * The subslice disable field is global, i.e. it applies498	 * to each of the enabled slices.499	 */500	subslice_mask = GENMASK(sseu->max_subslices - 1, 0);501	subslice_mask &= ~((fuse2 & GEN8_F2_SS_DIS_MASK) >>502			   GEN8_F2_SS_DIS_SHIFT);503	eu_disable0 = intel_uncore_read(uncore, GEN8_EU_DISABLE0);504	eu_disable1 = intel_uncore_read(uncore, GEN8_EU_DISABLE1);505	eu_disable2 = intel_uncore_read(uncore, GEN8_EU_DISABLE2);506	eu_disable[0] = eu_disable0 & GEN8_EU_DIS0_S0_MASK;507	eu_disable[1] = (eu_disable0 >> GEN8_EU_DIS0_S1_SHIFT) |508		((eu_disable1 & GEN8_EU_DIS1_S1_MASK) <<509		 (32 - GEN8_EU_DIS0_S1_SHIFT));510	eu_disable[2] = (eu_disable1 >> GEN8_EU_DIS1_S2_SHIFT) |511		((eu_disable2 & GEN8_EU_DIS2_S2_MASK) <<512		 (32 - GEN8_EU_DIS1_S2_SHIFT));513 514	/*515	 * Iterate through enabled slices and subslices to516	 * count the total enabled EU.517	 */518	for (s = 0; s < sseu->max_slices; s++) {519		if (!(sseu->slice_mask & BIT(s)))520			/* skip disabled slice */521			continue;522 523		sseu->subslice_mask.hsw[s] = subslice_mask;524 525		for (ss = 0; ss < sseu->max_subslices; ss++) {526			u8 eu_disabled_mask;527			u32 n_disabled;528 529			if (!intel_sseu_has_subslice(sseu, s, ss))530				/* skip disabled subslice */531				continue;532 533			eu_disabled_mask =534				eu_disable[s] >> (ss * sseu->max_eus_per_subslice);535 536			sseu_set_eus(sseu, s, ss, ~eu_disabled_mask & 0xFF);537 538			n_disabled = hweight8(eu_disabled_mask);539 540			/*541			 * Record which subslices have 7 EUs.542			 */543			if (sseu->max_eus_per_subslice - n_disabled == 7)544				sseu->subslice_7eu[s] |= 1 << ss;545		}546	}547 548	sseu->eu_total = compute_eu_total(sseu);549 550	/*551	 * BDW is expected to always have a uniform distribution of EU across552	 * subslices with the exception that any one EU in any one subslice may553	 * be fused off for die recovery.554	 */555	sseu->eu_per_subslice =556		intel_sseu_subslice_total(sseu) ?557		DIV_ROUND_UP(sseu->eu_total, intel_sseu_subslice_total(sseu)) :558		0;559 560	/*561	 * BDW supports slice power gating on devices with more than562	 * one slice.563	 */564	sseu->has_slice_pg = hweight8(sseu->slice_mask) > 1;565	sseu->has_subslice_pg = 0;566	sseu->has_eu_pg = 0;567}568 569static void hsw_sseu_info_init(struct intel_gt *gt)570{571	struct drm_i915_private *i915 = gt->i915;572	struct sseu_dev_info *sseu = &gt->info.sseu;573	u32 fuse1;574	u8 subslice_mask = 0;575	int s, ss;576 577	/*578	 * There isn't a register to tell us how many slices/subslices. We579	 * work off the PCI-ids here.580	 */581	switch (INTEL_INFO(i915)->gt) {582	default:583		MISSING_CASE(INTEL_INFO(i915)->gt);584		fallthrough;585	case 1:586		sseu->slice_mask = BIT(0);587		subslice_mask = BIT(0);588		break;589	case 2:590		sseu->slice_mask = BIT(0);591		subslice_mask = BIT(0) | BIT(1);592		break;593	case 3:594		sseu->slice_mask = BIT(0) | BIT(1);595		subslice_mask = BIT(0) | BIT(1);596		break;597	}598 599	fuse1 = intel_uncore_read(gt->uncore, HSW_PAVP_FUSE1);600	switch (REG_FIELD_GET(HSW_F1_EU_DIS_MASK, fuse1)) {601	default:602		MISSING_CASE(REG_FIELD_GET(HSW_F1_EU_DIS_MASK, fuse1));603		fallthrough;604	case HSW_F1_EU_DIS_10EUS:605		sseu->eu_per_subslice = 10;606		break;607	case HSW_F1_EU_DIS_8EUS:608		sseu->eu_per_subslice = 8;609		break;610	case HSW_F1_EU_DIS_6EUS:611		sseu->eu_per_subslice = 6;612		break;613	}614 615	intel_sseu_set_info(sseu, hweight8(sseu->slice_mask),616			    hweight8(subslice_mask),617			    sseu->eu_per_subslice);618 619	for (s = 0; s < sseu->max_slices; s++) {620		sseu->subslice_mask.hsw[s] = subslice_mask;621 622		for (ss = 0; ss < sseu->max_subslices; ss++) {623			sseu_set_eus(sseu, s, ss,624				     (1UL << sseu->eu_per_subslice) - 1);625		}626	}627 628	sseu->eu_total = compute_eu_total(sseu);629 630	/* No powergating for you. */631	sseu->has_slice_pg = 0;632	sseu->has_subslice_pg = 0;633	sseu->has_eu_pg = 0;634}635 636void intel_sseu_info_init(struct intel_gt *gt)637{638	struct drm_i915_private *i915 = gt->i915;639 640	if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 55))641		xehp_sseu_info_init(gt);642	else if (GRAPHICS_VER(i915) >= 12)643		gen12_sseu_info_init(gt);644	else if (GRAPHICS_VER(i915) >= 11)645		gen11_sseu_info_init(gt);646	else if (GRAPHICS_VER(i915) >= 9)647		gen9_sseu_info_init(gt);648	else if (IS_BROADWELL(i915))649		bdw_sseu_info_init(gt);650	else if (IS_CHERRYVIEW(i915))651		cherryview_sseu_info_init(gt);652	else if (IS_HASWELL(i915))653		hsw_sseu_info_init(gt);654}655 656u32 intel_sseu_make_rpcs(struct intel_gt *gt,657			 const struct intel_sseu *req_sseu)658{659	struct drm_i915_private *i915 = gt->i915;660	const struct sseu_dev_info *sseu = &gt->info.sseu;661	bool subslice_pg = sseu->has_subslice_pg;662	u8 slices, subslices;663	u32 rpcs = 0;664 665	/*666	 * No explicit RPCS request is needed to ensure full667	 * slice/subslice/EU enablement prior to Gen9.668	 */669	if (GRAPHICS_VER(i915) < 9)670		return 0;671 672	/*673	 * If i915/perf is active, we want a stable powergating configuration674	 * on the system. Use the configuration pinned by i915/perf.675	 */676	if (gt->perf.group && gt->perf.group[PERF_GROUP_OAG].exclusive_stream)677		req_sseu = &gt->perf.sseu;678 679	slices = hweight8(req_sseu->slice_mask);680	subslices = hweight8(req_sseu->subslice_mask);681 682	/*683	 * Since the SScount bitfield in GEN8_R_PWR_CLK_STATE is only three bits684	 * wide and Icelake has up to eight subslices, specfial programming is685	 * needed in order to correctly enable all subslices.686	 *687	 * According to documentation software must consider the configuration688	 * as 2x4x8 and hardware will translate this to 1x8x8.689	 *690	 * Furthemore, even though SScount is three bits, maximum documented691	 * value for it is four. From this some rules/restrictions follow:692	 *693	 * 1.694	 * If enabled subslice count is greater than four, two whole slices must695	 * be enabled instead.696	 *697	 * 2.698	 * When more than one slice is enabled, hardware ignores the subslice699	 * count altogether.700	 *701	 * From these restrictions it follows that it is not possible to enable702	 * a count of subslices between the SScount maximum of four restriction,703	 * and the maximum available number on a particular SKU. Either all704	 * subslices are enabled, or a count between one and four on the first705	 * slice.706	 */707	if (GRAPHICS_VER(i915) == 11 &&708	    slices == 1 &&709	    subslices > min_t(u8, 4, hweight8(sseu->subslice_mask.hsw[0]) / 2)) {710		GEM_BUG_ON(subslices & 1);711 712		subslice_pg = false;713		slices *= 2;714	}715 716	/*717	 * Starting in Gen9, render power gating can leave718	 * slice/subslice/EU in a partially enabled state. We719	 * must make an explicit request through RPCS for full720	 * enablement.721	 */722	if (sseu->has_slice_pg) {723		u32 mask, val = slices;724 725		if (GRAPHICS_VER(i915) >= 11) {726			mask = GEN11_RPCS_S_CNT_MASK;727			val <<= GEN11_RPCS_S_CNT_SHIFT;728		} else {729			mask = GEN8_RPCS_S_CNT_MASK;730			val <<= GEN8_RPCS_S_CNT_SHIFT;731		}732 733		GEM_BUG_ON(val & ~mask);734		val &= mask;735 736		rpcs |= GEN8_RPCS_ENABLE | GEN8_RPCS_S_CNT_ENABLE | val;737	}738 739	if (subslice_pg) {740		u32 val = subslices;741 742		val <<= GEN8_RPCS_SS_CNT_SHIFT;743 744		GEM_BUG_ON(val & ~GEN8_RPCS_SS_CNT_MASK);745		val &= GEN8_RPCS_SS_CNT_MASK;746 747		rpcs |= GEN8_RPCS_ENABLE | GEN8_RPCS_SS_CNT_ENABLE | val;748	}749 750	if (sseu->has_eu_pg) {751		u32 val;752 753		val = req_sseu->min_eus_per_subslice << GEN8_RPCS_EU_MIN_SHIFT;754		GEM_BUG_ON(val & ~GEN8_RPCS_EU_MIN_MASK);755		val &= GEN8_RPCS_EU_MIN_MASK;756 757		rpcs |= val;758 759		val = req_sseu->max_eus_per_subslice << GEN8_RPCS_EU_MAX_SHIFT;760		GEM_BUG_ON(val & ~GEN8_RPCS_EU_MAX_MASK);761		val &= GEN8_RPCS_EU_MAX_MASK;762 763		rpcs |= val;764 765		rpcs |= GEN8_RPCS_ENABLE;766	}767 768	return rpcs;769}770 771void intel_sseu_dump(const struct sseu_dev_info *sseu, struct drm_printer *p)772{773	int s;774 775	if (sseu->has_xehp_dss) {776		drm_printf(p, "subslice total: %u\n",777			   intel_sseu_subslice_total(sseu));778		drm_printf(p, "geometry dss mask=%*pb\n",779			   XEHP_BITMAP_BITS(sseu->geometry_subslice_mask),780			   sseu->geometry_subslice_mask.xehp);781		drm_printf(p, "compute dss mask=%*pb\n",782			   XEHP_BITMAP_BITS(sseu->compute_subslice_mask),783			   sseu->compute_subslice_mask.xehp);784	} else {785		drm_printf(p, "slice total: %u, mask=%04x\n",786			   hweight8(sseu->slice_mask), sseu->slice_mask);787		drm_printf(p, "subslice total: %u\n",788			   intel_sseu_subslice_total(sseu));789 790		for (s = 0; s < sseu->max_slices; s++) {791			u8 ss_mask = sseu->subslice_mask.hsw[s];792 793			drm_printf(p, "slice%d: %u subslices, mask=%08x\n",794				   s, hweight8(ss_mask), ss_mask);795		}796	}797 798	drm_printf(p, "EU total: %u\n", sseu->eu_total);799	drm_printf(p, "EU per subslice: %u\n", sseu->eu_per_subslice);800	drm_printf(p, "has slice power gating: %s\n",801		   str_yes_no(sseu->has_slice_pg));802	drm_printf(p, "has subslice power gating: %s\n",803		   str_yes_no(sseu->has_subslice_pg));804	drm_printf(p, "has EU power gating: %s\n",805		   str_yes_no(sseu->has_eu_pg));806}807 808static void sseu_print_hsw_topology(const struct sseu_dev_info *sseu,809				    struct drm_printer *p)810{811	int s, ss;812 813	for (s = 0; s < sseu->max_slices; s++) {814		u8 ss_mask = sseu->subslice_mask.hsw[s];815 816		drm_printf(p, "slice%d: %u subslice(s) (0x%08x):\n",817			   s, hweight8(ss_mask), ss_mask);818 819		for (ss = 0; ss < sseu->max_subslices; ss++) {820			u16 enabled_eus = sseu_get_eus(sseu, s, ss);821 822			drm_printf(p, "\tsubslice%d: %u EUs (0x%hx)\n",823				   ss, hweight16(enabled_eus), enabled_eus);824		}825	}826}827 828static void sseu_print_xehp_topology(const struct sseu_dev_info *sseu,829				     struct drm_printer *p)830{831	int dss;832 833	for (dss = 0; dss < sseu->max_subslices; dss++) {834		u16 enabled_eus = sseu_get_eus(sseu, 0, dss);835 836		drm_printf(p, "DSS_%02d: G:%3s C:%3s, %2u EUs (0x%04hx)\n", dss,837			   str_yes_no(test_bit(dss, sseu->geometry_subslice_mask.xehp)),838			   str_yes_no(test_bit(dss, sseu->compute_subslice_mask.xehp)),839			   hweight16(enabled_eus), enabled_eus);840	}841}842 843void intel_sseu_print_topology(struct drm_i915_private *i915,844			       const struct sseu_dev_info *sseu,845			       struct drm_printer *p)846{847	if (sseu->max_slices == 0)848		drm_printf(p, "Unavailable\n");849	else if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 55))850		sseu_print_xehp_topology(sseu, p);851	else852		sseu_print_hsw_topology(sseu, p);853}854 855void intel_sseu_print_ss_info(const char *type,856			      const struct sseu_dev_info *sseu,857			      struct seq_file *m)858{859	int s;860 861	if (sseu->has_xehp_dss) {862		seq_printf(m, "  %s Geometry DSS: %u\n", type,863			   bitmap_weight(sseu->geometry_subslice_mask.xehp,864					 XEHP_BITMAP_BITS(sseu->geometry_subslice_mask)));865		seq_printf(m, "  %s Compute DSS: %u\n", type,866			   bitmap_weight(sseu->compute_subslice_mask.xehp,867					 XEHP_BITMAP_BITS(sseu->compute_subslice_mask)));868	} else {869		for (s = 0; s < fls(sseu->slice_mask); s++)870			seq_printf(m, "  %s Slice%i subslices: %u\n", type,871				   s, hweight8(sseu->subslice_mask.hsw[s]));872	}873}874 875u16 intel_slicemask_from_xehp_dssmask(intel_sseu_ss_mask_t dss_mask,876				      int dss_per_slice)877{878	intel_sseu_ss_mask_t per_slice_mask = {};879	unsigned long slice_mask = 0;880	int i;881 882	WARN_ON(DIV_ROUND_UP(XEHP_BITMAP_BITS(dss_mask), dss_per_slice) >883		8 * sizeof(slice_mask));884 885	bitmap_fill(per_slice_mask.xehp, dss_per_slice);886	for (i = 0; !bitmap_empty(dss_mask.xehp, XEHP_BITMAP_BITS(dss_mask)); i++) {887		if (bitmap_intersects(dss_mask.xehp, per_slice_mask.xehp, dss_per_slice))888			slice_mask |= BIT(i);889 890		bitmap_shift_right(dss_mask.xehp, dss_mask.xehp, dss_per_slice,891				   XEHP_BITMAP_BITS(dss_mask));892	}893 894	return slice_mask;895}896