cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

intel_sseu.c (21947B)


      1// SPDX-License-Identifier: MIT
      2/*
      3 * Copyright © 2019 Intel Corporation
      4 */
      5
      6#include <linux/string_helpers.h>
      7
      8#include "i915_drv.h"
      9#include "intel_engine_regs.h"
     10#include "intel_gt_regs.h"
     11#include "intel_sseu.h"
     12
     13void intel_sseu_set_info(struct sseu_dev_info *sseu, u8 max_slices,
     14			 u8 max_subslices, u8 max_eus_per_subslice)
     15{
     16	sseu->max_slices = max_slices;
     17	sseu->max_subslices = max_subslices;
     18	sseu->max_eus_per_subslice = max_eus_per_subslice;
     19
     20	sseu->ss_stride = GEN_SSEU_STRIDE(sseu->max_subslices);
     21	GEM_BUG_ON(sseu->ss_stride > GEN_MAX_SUBSLICE_STRIDE);
     22	sseu->eu_stride = GEN_SSEU_STRIDE(sseu->max_eus_per_subslice);
     23	GEM_BUG_ON(sseu->eu_stride > GEN_MAX_EU_STRIDE);
     24}
     25
     26unsigned int
     27intel_sseu_subslice_total(const struct sseu_dev_info *sseu)
     28{
     29	unsigned int i, total = 0;
     30
     31	for (i = 0; i < ARRAY_SIZE(sseu->subslice_mask); i++)
     32		total += hweight8(sseu->subslice_mask[i]);
     33
     34	return total;
     35}
     36
     37static u32
     38sseu_get_subslices(const struct sseu_dev_info *sseu,
     39		   const u8 *subslice_mask, u8 slice)
     40{
     41	int i, offset = slice * sseu->ss_stride;
     42	u32 mask = 0;
     43
     44	GEM_BUG_ON(slice >= sseu->max_slices);
     45
     46	for (i = 0; i < sseu->ss_stride; i++)
     47		mask |= (u32)subslice_mask[offset + i] << i * BITS_PER_BYTE;
     48
     49	return mask;
     50}
     51
     52u32 intel_sseu_get_subslices(const struct sseu_dev_info *sseu, u8 slice)
     53{
     54	return sseu_get_subslices(sseu, sseu->subslice_mask, slice);
     55}
     56
     57static u32 sseu_get_geometry_subslices(const struct sseu_dev_info *sseu)
     58{
     59	return sseu_get_subslices(sseu, sseu->geometry_subslice_mask, 0);
     60}
     61
     62u32 intel_sseu_get_compute_subslices(const struct sseu_dev_info *sseu)
     63{
     64	return sseu_get_subslices(sseu, sseu->compute_subslice_mask, 0);
     65}
     66
     67void intel_sseu_set_subslices(struct sseu_dev_info *sseu, int slice,
     68			      u8 *subslice_mask, u32 ss_mask)
     69{
     70	int offset = slice * sseu->ss_stride;
     71
     72	memcpy(&subslice_mask[offset], &ss_mask, sseu->ss_stride);
     73}
     74
     75unsigned int
     76intel_sseu_subslices_per_slice(const struct sseu_dev_info *sseu, u8 slice)
     77{
     78	return hweight32(intel_sseu_get_subslices(sseu, slice));
     79}
     80
     81static int sseu_eu_idx(const struct sseu_dev_info *sseu, int slice,
     82		       int subslice)
     83{
     84	int slice_stride = sseu->max_subslices * sseu->eu_stride;
     85
     86	return slice * slice_stride + subslice * sseu->eu_stride;
     87}
     88
     89static u16 sseu_get_eus(const struct sseu_dev_info *sseu, int slice,
     90			int subslice)
     91{
     92	int i, offset = sseu_eu_idx(sseu, slice, subslice);
     93	u16 eu_mask = 0;
     94
     95	for (i = 0; i < sseu->eu_stride; i++)
     96		eu_mask |=
     97			((u16)sseu->eu_mask[offset + i]) << (i * BITS_PER_BYTE);
     98
     99	return eu_mask;
    100}
    101
    102static void sseu_set_eus(struct sseu_dev_info *sseu, int slice, int subslice,
    103			 u16 eu_mask)
    104{
    105	int i, offset = sseu_eu_idx(sseu, slice, subslice);
    106
    107	for (i = 0; i < sseu->eu_stride; i++)
    108		sseu->eu_mask[offset + i] =
    109			(eu_mask >> (BITS_PER_BYTE * i)) & 0xff;
    110}
    111
    112static u16 compute_eu_total(const struct sseu_dev_info *sseu)
    113{
    114	u16 i, total = 0;
    115
    116	for (i = 0; i < ARRAY_SIZE(sseu->eu_mask); i++)
    117		total += hweight8(sseu->eu_mask[i]);
    118
    119	return total;
    120}
    121
    122static u32 get_ss_stride_mask(struct sseu_dev_info *sseu, u8 s, u32 ss_en)
    123{
    124	u32 ss_mask;
    125
    126	ss_mask = ss_en >> (s * sseu->max_subslices);
    127	ss_mask &= GENMASK(sseu->max_subslices - 1, 0);
    128
    129	return ss_mask;
    130}
    131
    132static void gen11_compute_sseu_info(struct sseu_dev_info *sseu, u8 s_en,
    133				    u32 g_ss_en, u32 c_ss_en, u16 eu_en)
    134{
    135	int s, ss;
    136
    137	/* g_ss_en/c_ss_en represent entire subslice mask across all slices */
    138	GEM_BUG_ON(sseu->max_slices * sseu->max_subslices >
    139		   sizeof(g_ss_en) * BITS_PER_BYTE);
    140
    141	for (s = 0; s < sseu->max_slices; s++) {
    142		if ((s_en & BIT(s)) == 0)
    143			continue;
    144
    145		sseu->slice_mask |= BIT(s);
    146
    147		/*
    148		 * XeHP introduces the concept of compute vs geometry DSS. To
    149		 * reduce variation between GENs around subslice usage, store a
    150		 * mask for both the geometry and compute enabled masks since
    151		 * userspace will need to be able to query these masks
    152		 * independently.  Also compute a total enabled subslice count
    153		 * for the purposes of selecting subslices to use in a
    154		 * particular GEM context.
    155		 */
    156		intel_sseu_set_subslices(sseu, s, sseu->compute_subslice_mask,
    157					 get_ss_stride_mask(sseu, s, c_ss_en));
    158		intel_sseu_set_subslices(sseu, s, sseu->geometry_subslice_mask,
    159					 get_ss_stride_mask(sseu, s, g_ss_en));
    160		intel_sseu_set_subslices(sseu, s, sseu->subslice_mask,
    161					 get_ss_stride_mask(sseu, s,
    162							    g_ss_en | c_ss_en));
    163
    164		for (ss = 0; ss < sseu->max_subslices; ss++)
    165			if (intel_sseu_has_subslice(sseu, s, ss))
    166				sseu_set_eus(sseu, s, ss, eu_en);
    167	}
    168	sseu->eu_per_subslice = hweight16(eu_en);
    169	sseu->eu_total = compute_eu_total(sseu);
    170}
    171
    172static void gen12_sseu_info_init(struct intel_gt *gt)
    173{
    174	struct sseu_dev_info *sseu = &gt->info.sseu;
    175	struct intel_uncore *uncore = gt->uncore;
    176	u32 g_dss_en, c_dss_en = 0;
    177	u16 eu_en = 0;
    178	u8 eu_en_fuse;
    179	u8 s_en;
    180	int eu;
    181
    182	/*
    183	 * Gen12 has Dual-Subslices, which behave similarly to 2 gen11 SS.
    184	 * Instead of splitting these, provide userspace with an array
    185	 * of DSS to more closely represent the hardware resource.
    186	 *
    187	 * In addition, the concept of slice has been removed in Xe_HP.
    188	 * To be compatible with prior generations, assume a single slice
    189	 * across the entire device. Then calculate out the DSS for each
    190	 * workload type within that software slice.
    191	 */
    192	if (IS_DG2(gt->i915) || IS_XEHPSDV(gt->i915))
    193		intel_sseu_set_info(sseu, 1, 32, 16);
    194	else
    195		intel_sseu_set_info(sseu, 1, 6, 16);
    196
    197	/*
    198	 * As mentioned above, Xe_HP does not have the concept of a slice.
    199	 * Enable one for software backwards compatibility.
    200	 */
    201	if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 50))
    202		s_en = 0x1;
    203	else
    204		s_en = intel_uncore_read(uncore, GEN11_GT_SLICE_ENABLE) &
    205		       GEN11_GT_S_ENA_MASK;
    206
    207	g_dss_en = intel_uncore_read(uncore, GEN12_GT_GEOMETRY_DSS_ENABLE);
    208	if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 50))
    209		c_dss_en = intel_uncore_read(uncore, GEN12_GT_COMPUTE_DSS_ENABLE);
    210
    211	/* one bit per pair of EUs */
    212	if (GRAPHICS_VER_FULL(gt->i915) >= IP_VER(12, 50))
    213		eu_en_fuse = intel_uncore_read(uncore, XEHP_EU_ENABLE) & XEHP_EU_ENA_MASK;
    214	else
    215		eu_en_fuse = ~(intel_uncore_read(uncore, GEN11_EU_DISABLE) &
    216			       GEN11_EU_DIS_MASK);
    217
    218	for (eu = 0; eu < sseu->max_eus_per_subslice / 2; eu++)
    219		if (eu_en_fuse & BIT(eu))
    220			eu_en |= BIT(eu * 2) | BIT(eu * 2 + 1);
    221
    222	gen11_compute_sseu_info(sseu, s_en, g_dss_en, c_dss_en, eu_en);
    223
    224	/* TGL only supports slice-level power gating */
    225	sseu->has_slice_pg = 1;
    226}
    227
    228static void gen11_sseu_info_init(struct intel_gt *gt)
    229{
    230	struct sseu_dev_info *sseu = &gt->info.sseu;
    231	struct intel_uncore *uncore = gt->uncore;
    232	u32 ss_en;
    233	u8 eu_en;
    234	u8 s_en;
    235
    236	if (IS_JSL_EHL(gt->i915))
    237		intel_sseu_set_info(sseu, 1, 4, 8);
    238	else
    239		intel_sseu_set_info(sseu, 1, 8, 8);
    240
    241	s_en = intel_uncore_read(uncore, GEN11_GT_SLICE_ENABLE) &
    242		GEN11_GT_S_ENA_MASK;
    243	ss_en = ~intel_uncore_read(uncore, GEN11_GT_SUBSLICE_DISABLE);
    244
    245	eu_en = ~(intel_uncore_read(uncore, GEN11_EU_DISABLE) &
    246		  GEN11_EU_DIS_MASK);
    247
    248	gen11_compute_sseu_info(sseu, s_en, ss_en, 0, eu_en);
    249
    250	/* ICL has no power gating restrictions. */
    251	sseu->has_slice_pg = 1;
    252	sseu->has_subslice_pg = 1;
    253	sseu->has_eu_pg = 1;
    254}
    255
    256static void cherryview_sseu_info_init(struct intel_gt *gt)
    257{
    258	struct sseu_dev_info *sseu = &gt->info.sseu;
    259	u32 fuse;
    260	u8 subslice_mask = 0;
    261
    262	fuse = intel_uncore_read(gt->uncore, CHV_FUSE_GT);
    263
    264	sseu->slice_mask = BIT(0);
    265	intel_sseu_set_info(sseu, 1, 2, 8);
    266
    267	if (!(fuse & CHV_FGT_DISABLE_SS0)) {
    268		u8 disabled_mask =
    269			((fuse & CHV_FGT_EU_DIS_SS0_R0_MASK) >>
    270			 CHV_FGT_EU_DIS_SS0_R0_SHIFT) |
    271			(((fuse & CHV_FGT_EU_DIS_SS0_R1_MASK) >>
    272			  CHV_FGT_EU_DIS_SS0_R1_SHIFT) << 4);
    273
    274		subslice_mask |= BIT(0);
    275		sseu_set_eus(sseu, 0, 0, ~disabled_mask);
    276	}
    277
    278	if (!(fuse & CHV_FGT_DISABLE_SS1)) {
    279		u8 disabled_mask =
    280			((fuse & CHV_FGT_EU_DIS_SS1_R0_MASK) >>
    281			 CHV_FGT_EU_DIS_SS1_R0_SHIFT) |
    282			(((fuse & CHV_FGT_EU_DIS_SS1_R1_MASK) >>
    283			  CHV_FGT_EU_DIS_SS1_R1_SHIFT) << 4);
    284
    285		subslice_mask |= BIT(1);
    286		sseu_set_eus(sseu, 0, 1, ~disabled_mask);
    287	}
    288
    289	intel_sseu_set_subslices(sseu, 0, sseu->subslice_mask, subslice_mask);
    290
    291	sseu->eu_total = compute_eu_total(sseu);
    292
    293	/*
    294	 * CHV expected to always have a uniform distribution of EU
    295	 * across subslices.
    296	 */
    297	sseu->eu_per_subslice = intel_sseu_subslice_total(sseu) ?
    298		sseu->eu_total /
    299		intel_sseu_subslice_total(sseu) :
    300		0;
    301	/*
    302	 * CHV supports subslice power gating on devices with more than
    303	 * one subslice, and supports EU power gating on devices with
    304	 * more than one EU pair per subslice.
    305	 */
    306	sseu->has_slice_pg = 0;
    307	sseu->has_subslice_pg = intel_sseu_subslice_total(sseu) > 1;
    308	sseu->has_eu_pg = (sseu->eu_per_subslice > 2);
    309}
    310
    311static void gen9_sseu_info_init(struct intel_gt *gt)
    312{
    313	struct drm_i915_private *i915 = gt->i915;
    314	struct intel_device_info *info = mkwrite_device_info(i915);
    315	struct sseu_dev_info *sseu = &gt->info.sseu;
    316	struct intel_uncore *uncore = gt->uncore;
    317	u32 fuse2, eu_disable, subslice_mask;
    318	const u8 eu_mask = 0xff;
    319	int s, ss;
    320
    321	fuse2 = intel_uncore_read(uncore, GEN8_FUSE2);
    322	sseu->slice_mask = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;
    323
    324	/* BXT has a single slice and at most 3 subslices. */
    325	intel_sseu_set_info(sseu, IS_GEN9_LP(i915) ? 1 : 3,
    326			    IS_GEN9_LP(i915) ? 3 : 4, 8);
    327
    328	/*
    329	 * The subslice disable field is global, i.e. it applies
    330	 * to each of the enabled slices.
    331	 */
    332	subslice_mask = (1 << sseu->max_subslices) - 1;
    333	subslice_mask &= ~((fuse2 & GEN9_F2_SS_DIS_MASK) >>
    334			   GEN9_F2_SS_DIS_SHIFT);
    335
    336	/*
    337	 * Iterate through enabled slices and subslices to
    338	 * count the total enabled EU.
    339	 */
    340	for (s = 0; s < sseu->max_slices; s++) {
    341		if (!(sseu->slice_mask & BIT(s)))
    342			/* skip disabled slice */
    343			continue;
    344
    345		intel_sseu_set_subslices(sseu, s, sseu->subslice_mask,
    346					 subslice_mask);
    347
    348		eu_disable = intel_uncore_read(uncore, GEN9_EU_DISABLE(s));
    349		for (ss = 0; ss < sseu->max_subslices; ss++) {
    350			int eu_per_ss;
    351			u8 eu_disabled_mask;
    352
    353			if (!intel_sseu_has_subslice(sseu, s, ss))
    354				/* skip disabled subslice */
    355				continue;
    356
    357			eu_disabled_mask = (eu_disable >> (ss * 8)) & eu_mask;
    358
    359			sseu_set_eus(sseu, s, ss, ~eu_disabled_mask);
    360
    361			eu_per_ss = sseu->max_eus_per_subslice -
    362				hweight8(eu_disabled_mask);
    363
    364			/*
    365			 * Record which subslice(s) has(have) 7 EUs. we
    366			 * can tune the hash used to spread work among
    367			 * subslices if they are unbalanced.
    368			 */
    369			if (eu_per_ss == 7)
    370				sseu->subslice_7eu[s] |= BIT(ss);
    371		}
    372	}
    373
    374	sseu->eu_total = compute_eu_total(sseu);
    375
    376	/*
    377	 * SKL is expected to always have a uniform distribution
    378	 * of EU across subslices with the exception that any one
    379	 * EU in any one subslice may be fused off for die
    380	 * recovery. BXT is expected to be perfectly uniform in EU
    381	 * distribution.
    382	 */
    383	sseu->eu_per_subslice =
    384		intel_sseu_subslice_total(sseu) ?
    385		DIV_ROUND_UP(sseu->eu_total, intel_sseu_subslice_total(sseu)) :
    386		0;
    387
    388	/*
    389	 * SKL+ supports slice power gating on devices with more than
    390	 * one slice, and supports EU power gating on devices with
    391	 * more than one EU pair per subslice. BXT+ supports subslice
    392	 * power gating on devices with more than one subslice, and
    393	 * supports EU power gating on devices with more than one EU
    394	 * pair per subslice.
    395	 */
    396	sseu->has_slice_pg =
    397		!IS_GEN9_LP(i915) && hweight8(sseu->slice_mask) > 1;
    398	sseu->has_subslice_pg =
    399		IS_GEN9_LP(i915) && intel_sseu_subslice_total(sseu) > 1;
    400	sseu->has_eu_pg = sseu->eu_per_subslice > 2;
    401
    402	if (IS_GEN9_LP(i915)) {
    403#define IS_SS_DISABLED(ss)	(!(sseu->subslice_mask[0] & BIT(ss)))
    404		info->has_pooled_eu = hweight8(sseu->subslice_mask[0]) == 3;
    405
    406		sseu->min_eu_in_pool = 0;
    407		if (info->has_pooled_eu) {
    408			if (IS_SS_DISABLED(2) || IS_SS_DISABLED(0))
    409				sseu->min_eu_in_pool = 3;
    410			else if (IS_SS_DISABLED(1))
    411				sseu->min_eu_in_pool = 6;
    412			else
    413				sseu->min_eu_in_pool = 9;
    414		}
    415#undef IS_SS_DISABLED
    416	}
    417}
    418
    419static void bdw_sseu_info_init(struct intel_gt *gt)
    420{
    421	struct sseu_dev_info *sseu = &gt->info.sseu;
    422	struct intel_uncore *uncore = gt->uncore;
    423	int s, ss;
    424	u32 fuse2, subslice_mask, eu_disable[3]; /* s_max */
    425	u32 eu_disable0, eu_disable1, eu_disable2;
    426
    427	fuse2 = intel_uncore_read(uncore, GEN8_FUSE2);
    428	sseu->slice_mask = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;
    429	intel_sseu_set_info(sseu, 3, 3, 8);
    430
    431	/*
    432	 * The subslice disable field is global, i.e. it applies
    433	 * to each of the enabled slices.
    434	 */
    435	subslice_mask = GENMASK(sseu->max_subslices - 1, 0);
    436	subslice_mask &= ~((fuse2 & GEN8_F2_SS_DIS_MASK) >>
    437			   GEN8_F2_SS_DIS_SHIFT);
    438	eu_disable0 = intel_uncore_read(uncore, GEN8_EU_DISABLE0);
    439	eu_disable1 = intel_uncore_read(uncore, GEN8_EU_DISABLE1);
    440	eu_disable2 = intel_uncore_read(uncore, GEN8_EU_DISABLE2);
    441	eu_disable[0] = eu_disable0 & GEN8_EU_DIS0_S0_MASK;
    442	eu_disable[1] = (eu_disable0 >> GEN8_EU_DIS0_S1_SHIFT) |
    443		((eu_disable1 & GEN8_EU_DIS1_S1_MASK) <<
    444		 (32 - GEN8_EU_DIS0_S1_SHIFT));
    445	eu_disable[2] = (eu_disable1 >> GEN8_EU_DIS1_S2_SHIFT) |
    446		((eu_disable2 & GEN8_EU_DIS2_S2_MASK) <<
    447		 (32 - GEN8_EU_DIS1_S2_SHIFT));
    448
    449	/*
    450	 * Iterate through enabled slices and subslices to
    451	 * count the total enabled EU.
    452	 */
    453	for (s = 0; s < sseu->max_slices; s++) {
    454		if (!(sseu->slice_mask & BIT(s)))
    455			/* skip disabled slice */
    456			continue;
    457
    458		intel_sseu_set_subslices(sseu, s, sseu->subslice_mask,
    459					 subslice_mask);
    460
    461		for (ss = 0; ss < sseu->max_subslices; ss++) {
    462			u8 eu_disabled_mask;
    463			u32 n_disabled;
    464
    465			if (!intel_sseu_has_subslice(sseu, s, ss))
    466				/* skip disabled subslice */
    467				continue;
    468
    469			eu_disabled_mask =
    470				eu_disable[s] >> (ss * sseu->max_eus_per_subslice);
    471
    472			sseu_set_eus(sseu, s, ss, ~eu_disabled_mask);
    473
    474			n_disabled = hweight8(eu_disabled_mask);
    475
    476			/*
    477			 * Record which subslices have 7 EUs.
    478			 */
    479			if (sseu->max_eus_per_subslice - n_disabled == 7)
    480				sseu->subslice_7eu[s] |= 1 << ss;
    481		}
    482	}
    483
    484	sseu->eu_total = compute_eu_total(sseu);
    485
    486	/*
    487	 * BDW is expected to always have a uniform distribution of EU across
    488	 * subslices with the exception that any one EU in any one subslice may
    489	 * be fused off for die recovery.
    490	 */
    491	sseu->eu_per_subslice =
    492		intel_sseu_subslice_total(sseu) ?
    493		DIV_ROUND_UP(sseu->eu_total, intel_sseu_subslice_total(sseu)) :
    494		0;
    495
    496	/*
    497	 * BDW supports slice power gating on devices with more than
    498	 * one slice.
    499	 */
    500	sseu->has_slice_pg = hweight8(sseu->slice_mask) > 1;
    501	sseu->has_subslice_pg = 0;
    502	sseu->has_eu_pg = 0;
    503}
    504
    505static void hsw_sseu_info_init(struct intel_gt *gt)
    506{
    507	struct drm_i915_private *i915 = gt->i915;
    508	struct sseu_dev_info *sseu = &gt->info.sseu;
    509	u32 fuse1;
    510	u8 subslice_mask = 0;
    511	int s, ss;
    512
    513	/*
    514	 * There isn't a register to tell us how many slices/subslices. We
    515	 * work off the PCI-ids here.
    516	 */
    517	switch (INTEL_INFO(i915)->gt) {
    518	default:
    519		MISSING_CASE(INTEL_INFO(i915)->gt);
    520		fallthrough;
    521	case 1:
    522		sseu->slice_mask = BIT(0);
    523		subslice_mask = BIT(0);
    524		break;
    525	case 2:
    526		sseu->slice_mask = BIT(0);
    527		subslice_mask = BIT(0) | BIT(1);
    528		break;
    529	case 3:
    530		sseu->slice_mask = BIT(0) | BIT(1);
    531		subslice_mask = BIT(0) | BIT(1);
    532		break;
    533	}
    534
    535	fuse1 = intel_uncore_read(gt->uncore, HSW_PAVP_FUSE1);
    536	switch (REG_FIELD_GET(HSW_F1_EU_DIS_MASK, fuse1)) {
    537	default:
    538		MISSING_CASE(REG_FIELD_GET(HSW_F1_EU_DIS_MASK, fuse1));
    539		fallthrough;
    540	case HSW_F1_EU_DIS_10EUS:
    541		sseu->eu_per_subslice = 10;
    542		break;
    543	case HSW_F1_EU_DIS_8EUS:
    544		sseu->eu_per_subslice = 8;
    545		break;
    546	case HSW_F1_EU_DIS_6EUS:
    547		sseu->eu_per_subslice = 6;
    548		break;
    549	}
    550
    551	intel_sseu_set_info(sseu, hweight8(sseu->slice_mask),
    552			    hweight8(subslice_mask),
    553			    sseu->eu_per_subslice);
    554
    555	for (s = 0; s < sseu->max_slices; s++) {
    556		intel_sseu_set_subslices(sseu, s, sseu->subslice_mask,
    557					 subslice_mask);
    558
    559		for (ss = 0; ss < sseu->max_subslices; ss++) {
    560			sseu_set_eus(sseu, s, ss,
    561				     (1UL << sseu->eu_per_subslice) - 1);
    562		}
    563	}
    564
    565	sseu->eu_total = compute_eu_total(sseu);
    566
    567	/* No powergating for you. */
    568	sseu->has_slice_pg = 0;
    569	sseu->has_subslice_pg = 0;
    570	sseu->has_eu_pg = 0;
    571}
    572
    573void intel_sseu_info_init(struct intel_gt *gt)
    574{
    575	struct drm_i915_private *i915 = gt->i915;
    576
    577	if (IS_HASWELL(i915))
    578		hsw_sseu_info_init(gt);
    579	else if (IS_CHERRYVIEW(i915))
    580		cherryview_sseu_info_init(gt);
    581	else if (IS_BROADWELL(i915))
    582		bdw_sseu_info_init(gt);
    583	else if (GRAPHICS_VER(i915) == 9)
    584		gen9_sseu_info_init(gt);
    585	else if (GRAPHICS_VER(i915) == 11)
    586		gen11_sseu_info_init(gt);
    587	else if (GRAPHICS_VER(i915) >= 12)
    588		gen12_sseu_info_init(gt);
    589}
    590
    591u32 intel_sseu_make_rpcs(struct intel_gt *gt,
    592			 const struct intel_sseu *req_sseu)
    593{
    594	struct drm_i915_private *i915 = gt->i915;
    595	const struct sseu_dev_info *sseu = &gt->info.sseu;
    596	bool subslice_pg = sseu->has_subslice_pg;
    597	u8 slices, subslices;
    598	u32 rpcs = 0;
    599
    600	/*
    601	 * No explicit RPCS request is needed to ensure full
    602	 * slice/subslice/EU enablement prior to Gen9.
    603	 */
    604	if (GRAPHICS_VER(i915) < 9)
    605		return 0;
    606
    607	/*
    608	 * If i915/perf is active, we want a stable powergating configuration
    609	 * on the system. Use the configuration pinned by i915/perf.
    610	 */
    611	if (i915->perf.exclusive_stream)
    612		req_sseu = &i915->perf.sseu;
    613
    614	slices = hweight8(req_sseu->slice_mask);
    615	subslices = hweight8(req_sseu->subslice_mask);
    616
    617	/*
    618	 * Since the SScount bitfield in GEN8_R_PWR_CLK_STATE is only three bits
    619	 * wide and Icelake has up to eight subslices, specfial programming is
    620	 * needed in order to correctly enable all subslices.
    621	 *
    622	 * According to documentation software must consider the configuration
    623	 * as 2x4x8 and hardware will translate this to 1x8x8.
    624	 *
    625	 * Furthemore, even though SScount is three bits, maximum documented
    626	 * value for it is four. From this some rules/restrictions follow:
    627	 *
    628	 * 1.
    629	 * If enabled subslice count is greater than four, two whole slices must
    630	 * be enabled instead.
    631	 *
    632	 * 2.
    633	 * When more than one slice is enabled, hardware ignores the subslice
    634	 * count altogether.
    635	 *
    636	 * From these restrictions it follows that it is not possible to enable
    637	 * a count of subslices between the SScount maximum of four restriction,
    638	 * and the maximum available number on a particular SKU. Either all
    639	 * subslices are enabled, or a count between one and four on the first
    640	 * slice.
    641	 */
    642	if (GRAPHICS_VER(i915) == 11 &&
    643	    slices == 1 &&
    644	    subslices > min_t(u8, 4, hweight8(sseu->subslice_mask[0]) / 2)) {
    645		GEM_BUG_ON(subslices & 1);
    646
    647		subslice_pg = false;
    648		slices *= 2;
    649	}
    650
    651	/*
    652	 * Starting in Gen9, render power gating can leave
    653	 * slice/subslice/EU in a partially enabled state. We
    654	 * must make an explicit request through RPCS for full
    655	 * enablement.
    656	 */
    657	if (sseu->has_slice_pg) {
    658		u32 mask, val = slices;
    659
    660		if (GRAPHICS_VER(i915) >= 11) {
    661			mask = GEN11_RPCS_S_CNT_MASK;
    662			val <<= GEN11_RPCS_S_CNT_SHIFT;
    663		} else {
    664			mask = GEN8_RPCS_S_CNT_MASK;
    665			val <<= GEN8_RPCS_S_CNT_SHIFT;
    666		}
    667
    668		GEM_BUG_ON(val & ~mask);
    669		val &= mask;
    670
    671		rpcs |= GEN8_RPCS_ENABLE | GEN8_RPCS_S_CNT_ENABLE | val;
    672	}
    673
    674	if (subslice_pg) {
    675		u32 val = subslices;
    676
    677		val <<= GEN8_RPCS_SS_CNT_SHIFT;
    678
    679		GEM_BUG_ON(val & ~GEN8_RPCS_SS_CNT_MASK);
    680		val &= GEN8_RPCS_SS_CNT_MASK;
    681
    682		rpcs |= GEN8_RPCS_ENABLE | GEN8_RPCS_SS_CNT_ENABLE | val;
    683	}
    684
    685	if (sseu->has_eu_pg) {
    686		u32 val;
    687
    688		val = req_sseu->min_eus_per_subslice << GEN8_RPCS_EU_MIN_SHIFT;
    689		GEM_BUG_ON(val & ~GEN8_RPCS_EU_MIN_MASK);
    690		val &= GEN8_RPCS_EU_MIN_MASK;
    691
    692		rpcs |= val;
    693
    694		val = req_sseu->max_eus_per_subslice << GEN8_RPCS_EU_MAX_SHIFT;
    695		GEM_BUG_ON(val & ~GEN8_RPCS_EU_MAX_MASK);
    696		val &= GEN8_RPCS_EU_MAX_MASK;
    697
    698		rpcs |= val;
    699
    700		rpcs |= GEN8_RPCS_ENABLE;
    701	}
    702
    703	return rpcs;
    704}
    705
    706void intel_sseu_dump(const struct sseu_dev_info *sseu, struct drm_printer *p)
    707{
    708	int s;
    709
    710	drm_printf(p, "slice total: %u, mask=%04x\n",
    711		   hweight8(sseu->slice_mask), sseu->slice_mask);
    712	drm_printf(p, "subslice total: %u\n", intel_sseu_subslice_total(sseu));
    713	for (s = 0; s < sseu->max_slices; s++) {
    714		drm_printf(p, "slice%d: %u subslices, mask=%08x\n",
    715			   s, intel_sseu_subslices_per_slice(sseu, s),
    716			   intel_sseu_get_subslices(sseu, s));
    717	}
    718	drm_printf(p, "EU total: %u\n", sseu->eu_total);
    719	drm_printf(p, "EU per subslice: %u\n", sseu->eu_per_subslice);
    720	drm_printf(p, "has slice power gating: %s\n",
    721		   str_yes_no(sseu->has_slice_pg));
    722	drm_printf(p, "has subslice power gating: %s\n",
    723		   str_yes_no(sseu->has_subslice_pg));
    724	drm_printf(p, "has EU power gating: %s\n",
    725		   str_yes_no(sseu->has_eu_pg));
    726}
    727
    728static void sseu_print_hsw_topology(const struct sseu_dev_info *sseu,
    729				    struct drm_printer *p)
    730{
    731	int s, ss;
    732
    733	for (s = 0; s < sseu->max_slices; s++) {
    734		drm_printf(p, "slice%d: %u subslice(s) (0x%08x):\n",
    735			   s, intel_sseu_subslices_per_slice(sseu, s),
    736			   intel_sseu_get_subslices(sseu, s));
    737
    738		for (ss = 0; ss < sseu->max_subslices; ss++) {
    739			u16 enabled_eus = sseu_get_eus(sseu, s, ss);
    740
    741			drm_printf(p, "\tsubslice%d: %u EUs (0x%hx)\n",
    742				   ss, hweight16(enabled_eus), enabled_eus);
    743		}
    744	}
    745}
    746
    747static void sseu_print_xehp_topology(const struct sseu_dev_info *sseu,
    748				     struct drm_printer *p)
    749{
    750	u32 g_dss_mask = sseu_get_geometry_subslices(sseu);
    751	u32 c_dss_mask = intel_sseu_get_compute_subslices(sseu);
    752	int dss;
    753
    754	for (dss = 0; dss < sseu->max_subslices; dss++) {
    755		u16 enabled_eus = sseu_get_eus(sseu, 0, dss);
    756
    757		drm_printf(p, "DSS_%02d: G:%3s C:%3s, %2u EUs (0x%04hx)\n", dss,
    758			   str_yes_no(g_dss_mask & BIT(dss)),
    759			   str_yes_no(c_dss_mask & BIT(dss)),
    760			   hweight16(enabled_eus), enabled_eus);
    761	}
    762}
    763
    764void intel_sseu_print_topology(struct drm_i915_private *i915,
    765			       const struct sseu_dev_info *sseu,
    766			       struct drm_printer *p)
    767{
    768	if (sseu->max_slices == 0) {
    769		drm_printf(p, "Unavailable\n");
    770	} else if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) {
    771		sseu_print_xehp_topology(sseu, p);
    772	} else {
    773		sseu_print_hsw_topology(sseu, p);
    774	}
    775}
    776
    777u16 intel_slicemask_from_dssmask(u64 dss_mask, int dss_per_slice)
    778{
    779	u16 slice_mask = 0;
    780	int i;
    781
    782	WARN_ON(sizeof(dss_mask) * 8 / dss_per_slice > 8 * sizeof(slice_mask));
    783
    784	for (i = 0; dss_mask; i++) {
    785		if (dss_mask & GENMASK(dss_per_slice - 1, 0))
    786			slice_mask |= BIT(i);
    787
    788		dss_mask >>= dss_per_slice;
    789	}
    790
    791	return slice_mask;
    792}
    793