xref: /openbmc/linux/drivers/gpu/drm/i915/gt/intel_sseu.c (revision 4f727ece)
1 /*
2  * SPDX-License-Identifier: MIT
3  *
4  * Copyright © 2019 Intel Corporation
5  */
6 
7 #include "i915_drv.h"
8 #include "intel_lrc_reg.h"
9 #include "intel_sseu.h"
10 
11 unsigned int
12 intel_sseu_subslice_total(const struct sseu_dev_info *sseu)
13 {
14 	unsigned int i, total = 0;
15 
16 	for (i = 0; i < ARRAY_SIZE(sseu->subslice_mask); i++)
17 		total += hweight8(sseu->subslice_mask[i]);
18 
19 	return total;
20 }
21 
22 unsigned int
23 intel_sseu_subslices_per_slice(const struct sseu_dev_info *sseu, u8 slice)
24 {
25 	return hweight8(sseu->subslice_mask[slice]);
26 }
27 
28 u32 intel_sseu_make_rpcs(struct drm_i915_private *i915,
29 			 const struct intel_sseu *req_sseu)
30 {
31 	const struct sseu_dev_info *sseu = &RUNTIME_INFO(i915)->sseu;
32 	bool subslice_pg = sseu->has_subslice_pg;
33 	struct intel_sseu ctx_sseu;
34 	u8 slices, subslices;
35 	u32 rpcs = 0;
36 
37 	/*
38 	 * No explicit RPCS request is needed to ensure full
39 	 * slice/subslice/EU enablement prior to Gen9.
40 	 */
41 	if (INTEL_GEN(i915) < 9)
42 		return 0;
43 
44 	/*
45 	 * If i915/perf is active, we want a stable powergating configuration
46 	 * on the system.
47 	 *
48 	 * We could choose full enablement, but on ICL we know there are use
49 	 * cases which disable slices for functional, apart for performance
50 	 * reasons. So in this case we select a known stable subset.
51 	 */
52 	if (!i915->perf.oa.exclusive_stream) {
53 		ctx_sseu = *req_sseu;
54 	} else {
55 		ctx_sseu = intel_sseu_from_device_info(sseu);
56 
57 		if (IS_GEN(i915, 11)) {
58 			/*
59 			 * We only need subslice count so it doesn't matter
60 			 * which ones we select - just turn off low bits in the
61 			 * amount of half of all available subslices per slice.
62 			 */
63 			ctx_sseu.subslice_mask =
64 				~(~0 << (hweight8(ctx_sseu.subslice_mask) / 2));
65 			ctx_sseu.slice_mask = 0x1;
66 		}
67 	}
68 
69 	slices = hweight8(ctx_sseu.slice_mask);
70 	subslices = hweight8(ctx_sseu.subslice_mask);
71 
72 	/*
73 	 * Since the SScount bitfield in GEN8_R_PWR_CLK_STATE is only three bits
74 	 * wide and Icelake has up to eight subslices, specfial programming is
75 	 * needed in order to correctly enable all subslices.
76 	 *
77 	 * According to documentation software must consider the configuration
78 	 * as 2x4x8 and hardware will translate this to 1x8x8.
79 	 *
80 	 * Furthemore, even though SScount is three bits, maximum documented
81 	 * value for it is four. From this some rules/restrictions follow:
82 	 *
83 	 * 1.
84 	 * If enabled subslice count is greater than four, two whole slices must
85 	 * be enabled instead.
86 	 *
87 	 * 2.
88 	 * When more than one slice is enabled, hardware ignores the subslice
89 	 * count altogether.
90 	 *
91 	 * From these restrictions it follows that it is not possible to enable
92 	 * a count of subslices between the SScount maximum of four restriction,
93 	 * and the maximum available number on a particular SKU. Either all
94 	 * subslices are enabled, or a count between one and four on the first
95 	 * slice.
96 	 */
97 	if (IS_GEN(i915, 11) &&
98 	    slices == 1 &&
99 	    subslices > min_t(u8, 4, hweight8(sseu->subslice_mask[0]) / 2)) {
100 		GEM_BUG_ON(subslices & 1);
101 
102 		subslice_pg = false;
103 		slices *= 2;
104 	}
105 
106 	/*
107 	 * Starting in Gen9, render power gating can leave
108 	 * slice/subslice/EU in a partially enabled state. We
109 	 * must make an explicit request through RPCS for full
110 	 * enablement.
111 	 */
112 	if (sseu->has_slice_pg) {
113 		u32 mask, val = slices;
114 
115 		if (INTEL_GEN(i915) >= 11) {
116 			mask = GEN11_RPCS_S_CNT_MASK;
117 			val <<= GEN11_RPCS_S_CNT_SHIFT;
118 		} else {
119 			mask = GEN8_RPCS_S_CNT_MASK;
120 			val <<= GEN8_RPCS_S_CNT_SHIFT;
121 		}
122 
123 		GEM_BUG_ON(val & ~mask);
124 		val &= mask;
125 
126 		rpcs |= GEN8_RPCS_ENABLE | GEN8_RPCS_S_CNT_ENABLE | val;
127 	}
128 
129 	if (subslice_pg) {
130 		u32 val = subslices;
131 
132 		val <<= GEN8_RPCS_SS_CNT_SHIFT;
133 
134 		GEM_BUG_ON(val & ~GEN8_RPCS_SS_CNT_MASK);
135 		val &= GEN8_RPCS_SS_CNT_MASK;
136 
137 		rpcs |= GEN8_RPCS_ENABLE | GEN8_RPCS_SS_CNT_ENABLE | val;
138 	}
139 
140 	if (sseu->has_eu_pg) {
141 		u32 val;
142 
143 		val = ctx_sseu.min_eus_per_subslice << GEN8_RPCS_EU_MIN_SHIFT;
144 		GEM_BUG_ON(val & ~GEN8_RPCS_EU_MIN_MASK);
145 		val &= GEN8_RPCS_EU_MIN_MASK;
146 
147 		rpcs |= val;
148 
149 		val = ctx_sseu.max_eus_per_subslice << GEN8_RPCS_EU_MAX_SHIFT;
150 		GEM_BUG_ON(val & ~GEN8_RPCS_EU_MAX_MASK);
151 		val &= GEN8_RPCS_EU_MAX_MASK;
152 
153 		rpcs |= val;
154 
155 		rpcs |= GEN8_RPCS_ENABLE;
156 	}
157 
158 	return rpcs;
159 }
160