xref: /linux/drivers/gpu/drm/i915/gt/intel_sseu_debugfs.c (revision 815e260a18a3af4dab59025ee99a7156c0e8b5e0)
1 // SPDX-License-Identifier: MIT
2 
3 /*
4  * Copyright © 2020 Intel Corporation
5  */
6 
7 #include <linux/bitmap.h>
8 #include <linux/string_helpers.h>
9 
10 #include <drm/drm_print.h>
11 
12 #include "i915_drv.h"
13 #include "intel_gt_debugfs.h"
14 #include "intel_gt_regs.h"
15 #include "intel_sseu_debugfs.h"
16 
17 static void cherryview_sseu_device_status(struct intel_gt *gt,
18 					  struct sseu_dev_info *sseu)
19 {
20 #define SS_MAX 2
21 	struct intel_uncore *uncore = gt->uncore;
22 	const int ss_max = SS_MAX;
23 	u32 sig1[SS_MAX], sig2[SS_MAX];
24 	int ss;
25 
26 	sig1[0] = intel_uncore_read(uncore, CHV_POWER_SS0_SIG1);
27 	sig1[1] = intel_uncore_read(uncore, CHV_POWER_SS1_SIG1);
28 	sig2[0] = intel_uncore_read(uncore, CHV_POWER_SS0_SIG2);
29 	sig2[1] = intel_uncore_read(uncore, CHV_POWER_SS1_SIG2);
30 
31 	for (ss = 0; ss < ss_max; ss++) {
32 		unsigned int eu_cnt;
33 
34 		if (sig1[ss] & CHV_SS_PG_ENABLE)
35 			/* skip disabled subslice */
36 			continue;
37 
38 		sseu->slice_mask = BIT(0);
39 		sseu->subslice_mask.hsw[0] |= BIT(ss);
40 		eu_cnt = ((sig1[ss] & CHV_EU08_PG_ENABLE) ? 0 : 2) +
41 			 ((sig1[ss] & CHV_EU19_PG_ENABLE) ? 0 : 2) +
42 			 ((sig1[ss] & CHV_EU210_PG_ENABLE) ? 0 : 2) +
43 			 ((sig2[ss] & CHV_EU311_PG_ENABLE) ? 0 : 2);
44 		sseu->eu_total += eu_cnt;
45 		sseu->eu_per_subslice = max_t(unsigned int,
46 					      sseu->eu_per_subslice, eu_cnt);
47 	}
48 #undef SS_MAX
49 }
50 
51 static void gen11_sseu_device_status(struct intel_gt *gt,
52 				     struct sseu_dev_info *sseu)
53 {
54 #define SS_MAX 8
55 	struct intel_uncore *uncore = gt->uncore;
56 	const struct intel_gt_info *info = &gt->info;
57 	u32 s_reg[SS_MAX], eu_reg[2 * SS_MAX], eu_mask[2];
58 	int s, ss;
59 
60 	for (s = 0; s < info->sseu.max_slices; s++) {
61 		/*
62 		 * FIXME: Valid SS Mask respects the spec and read
63 		 * only valid bits for those registers, excluding reserved
64 		 * although this seems wrong because it would leave many
65 		 * subslices without ACK.
66 		 */
67 		s_reg[s] = intel_uncore_read(uncore, GEN10_SLICE_PGCTL_ACK(s)) &
68 			GEN10_PGCTL_VALID_SS_MASK(s);
69 		eu_reg[2 * s] = intel_uncore_read(uncore,
70 						  GEN10_SS01_EU_PGCTL_ACK(s));
71 		eu_reg[2 * s + 1] = intel_uncore_read(uncore,
72 						      GEN10_SS23_EU_PGCTL_ACK(s));
73 	}
74 
75 	eu_mask[0] = GEN9_PGCTL_SSA_EU08_ACK |
76 		     GEN9_PGCTL_SSA_EU19_ACK |
77 		     GEN9_PGCTL_SSA_EU210_ACK |
78 		     GEN9_PGCTL_SSA_EU311_ACK;
79 	eu_mask[1] = GEN9_PGCTL_SSB_EU08_ACK |
80 		     GEN9_PGCTL_SSB_EU19_ACK |
81 		     GEN9_PGCTL_SSB_EU210_ACK |
82 		     GEN9_PGCTL_SSB_EU311_ACK;
83 
84 	for (s = 0; s < info->sseu.max_slices; s++) {
85 		if ((s_reg[s] & GEN9_PGCTL_SLICE_ACK) == 0)
86 			/* skip disabled slice */
87 			continue;
88 
89 		sseu->slice_mask |= BIT(s);
90 		sseu->subslice_mask.hsw[s] = info->sseu.subslice_mask.hsw[s];
91 
92 		for (ss = 0; ss < info->sseu.max_subslices; ss++) {
93 			unsigned int eu_cnt;
94 
95 			if (info->sseu.has_subslice_pg &&
96 			    !(s_reg[s] & (GEN9_PGCTL_SS_ACK(ss))))
97 				/* skip disabled subslice */
98 				continue;
99 
100 			eu_cnt = 2 * hweight32(eu_reg[2 * s + ss / 2] &
101 					       eu_mask[ss % 2]);
102 			sseu->eu_total += eu_cnt;
103 			sseu->eu_per_subslice = max_t(unsigned int,
104 						      sseu->eu_per_subslice,
105 						      eu_cnt);
106 		}
107 	}
108 #undef SS_MAX
109 }
110 
111 static void gen9_sseu_device_status(struct intel_gt *gt,
112 				    struct sseu_dev_info *sseu)
113 {
114 #define SS_MAX 3
115 	struct intel_uncore *uncore = gt->uncore;
116 	const struct intel_gt_info *info = &gt->info;
117 	u32 s_reg[SS_MAX], eu_reg[2 * SS_MAX], eu_mask[2];
118 	int s, ss;
119 
120 	for (s = 0; s < info->sseu.max_slices; s++) {
121 		s_reg[s] = intel_uncore_read(uncore, GEN9_SLICE_PGCTL_ACK(s));
122 		eu_reg[2 * s] =
123 			intel_uncore_read(uncore, GEN9_SS01_EU_PGCTL_ACK(s));
124 		eu_reg[2 * s + 1] =
125 			intel_uncore_read(uncore, GEN9_SS23_EU_PGCTL_ACK(s));
126 	}
127 
128 	eu_mask[0] = GEN9_PGCTL_SSA_EU08_ACK |
129 		     GEN9_PGCTL_SSA_EU19_ACK |
130 		     GEN9_PGCTL_SSA_EU210_ACK |
131 		     GEN9_PGCTL_SSA_EU311_ACK;
132 	eu_mask[1] = GEN9_PGCTL_SSB_EU08_ACK |
133 		     GEN9_PGCTL_SSB_EU19_ACK |
134 		     GEN9_PGCTL_SSB_EU210_ACK |
135 		     GEN9_PGCTL_SSB_EU311_ACK;
136 
137 	for (s = 0; s < info->sseu.max_slices; s++) {
138 		if ((s_reg[s] & GEN9_PGCTL_SLICE_ACK) == 0)
139 			/* skip disabled slice */
140 			continue;
141 
142 		sseu->slice_mask |= BIT(s);
143 
144 		if (IS_GEN9_BC(gt->i915))
145 			sseu->subslice_mask.hsw[s] = info->sseu.subslice_mask.hsw[s];
146 
147 		for (ss = 0; ss < info->sseu.max_subslices; ss++) {
148 			unsigned int eu_cnt;
149 
150 			if (IS_GEN9_LP(gt->i915)) {
151 				if (!(s_reg[s] & (GEN9_PGCTL_SS_ACK(ss))))
152 					/* skip disabled subslice */
153 					continue;
154 
155 				sseu->subslice_mask.hsw[s] |= BIT(ss);
156 			}
157 
158 			eu_cnt = eu_reg[2 * s + ss / 2] & eu_mask[ss % 2];
159 			eu_cnt = 2 * hweight32(eu_cnt);
160 
161 			sseu->eu_total += eu_cnt;
162 			sseu->eu_per_subslice = max_t(unsigned int,
163 						      sseu->eu_per_subslice,
164 						      eu_cnt);
165 		}
166 	}
167 #undef SS_MAX
168 }
169 
170 static void bdw_sseu_device_status(struct intel_gt *gt,
171 				   struct sseu_dev_info *sseu)
172 {
173 	const struct intel_gt_info *info = &gt->info;
174 	u32 slice_info = intel_uncore_read(gt->uncore, GEN8_GT_SLICE_INFO);
175 	int s;
176 
177 	sseu->slice_mask = slice_info & GEN8_LSLICESTAT_MASK;
178 
179 	if (sseu->slice_mask) {
180 		sseu->eu_per_subslice = info->sseu.eu_per_subslice;
181 		for (s = 0; s < fls(sseu->slice_mask); s++)
182 			sseu->subslice_mask.hsw[s] = info->sseu.subslice_mask.hsw[s];
183 		sseu->eu_total = sseu->eu_per_subslice *
184 				 intel_sseu_subslice_total(sseu);
185 
186 		/* subtract fused off EU(s) from enabled slice(s) */
187 		for (s = 0; s < fls(sseu->slice_mask); s++) {
188 			u8 subslice_7eu = info->sseu.subslice_7eu[s];
189 
190 			sseu->eu_total -= hweight8(subslice_7eu);
191 		}
192 	}
193 }
194 
195 static void i915_print_sseu_info(struct seq_file *m,
196 				 bool is_available_info,
197 				 bool has_pooled_eu,
198 				 const struct sseu_dev_info *sseu)
199 {
200 	const char *type = is_available_info ? "Available" : "Enabled";
201 
202 	seq_printf(m, "  %s Slice Mask: %04x\n", type,
203 		   sseu->slice_mask);
204 	seq_printf(m, "  %s Slice Total: %u\n", type,
205 		   hweight8(sseu->slice_mask));
206 	seq_printf(m, "  %s Subslice Total: %u\n", type,
207 		   intel_sseu_subslice_total(sseu));
208 	intel_sseu_print_ss_info(type, sseu, m);
209 	seq_printf(m, "  %s EU Total: %u\n", type,
210 		   sseu->eu_total);
211 	seq_printf(m, "  %s EU Per Subslice: %u\n", type,
212 		   sseu->eu_per_subslice);
213 
214 	if (!is_available_info)
215 		return;
216 
217 	seq_printf(m, "  Has Pooled EU: %s\n", str_yes_no(has_pooled_eu));
218 	if (has_pooled_eu)
219 		seq_printf(m, "  Min EU in pool: %u\n", sseu->min_eu_in_pool);
220 
221 	seq_printf(m, "  Has Slice Power Gating: %s\n",
222 		   str_yes_no(sseu->has_slice_pg));
223 	seq_printf(m, "  Has Subslice Power Gating: %s\n",
224 		   str_yes_no(sseu->has_subslice_pg));
225 	seq_printf(m, "  Has EU Power Gating: %s\n",
226 		   str_yes_no(sseu->has_eu_pg));
227 }
228 
229 /*
230  * this is called from top-level debugfs as well, so we can't get the gt from
231  * the seq_file.
232  */
233 int intel_sseu_status(struct seq_file *m, struct intel_gt *gt)
234 {
235 	struct drm_i915_private *i915 = gt->i915;
236 	const struct intel_gt_info *info = &gt->info;
237 	struct sseu_dev_info *sseu;
238 	intel_wakeref_t wakeref;
239 
240 	if (GRAPHICS_VER(i915) < 8)
241 		return -ENODEV;
242 
243 	seq_puts(m, "SSEU Device Info\n");
244 	i915_print_sseu_info(m, true, HAS_POOLED_EU(i915), &info->sseu);
245 
246 	seq_puts(m, "SSEU Device Status\n");
247 
248 	sseu = kzalloc(sizeof(*sseu), GFP_KERNEL);
249 	if (!sseu)
250 		return -ENOMEM;
251 
252 	intel_sseu_set_info(sseu, info->sseu.max_slices,
253 			    info->sseu.max_subslices,
254 			    info->sseu.max_eus_per_subslice);
255 
256 	with_intel_runtime_pm(&i915->runtime_pm, wakeref) {
257 		if (IS_CHERRYVIEW(i915))
258 			cherryview_sseu_device_status(gt, sseu);
259 		else if (IS_BROADWELL(i915))
260 			bdw_sseu_device_status(gt, sseu);
261 		else if (GRAPHICS_VER(i915) == 9)
262 			gen9_sseu_device_status(gt, sseu);
263 		else if (GRAPHICS_VER(i915) >= 11)
264 			gen11_sseu_device_status(gt, sseu);
265 	}
266 
267 	i915_print_sseu_info(m, false, HAS_POOLED_EU(i915), sseu);
268 
269 	kfree(sseu);
270 
271 	return 0;
272 }
273 
274 static int sseu_status_show(struct seq_file *m, void *unused)
275 {
276 	struct intel_gt *gt = m->private;
277 
278 	return intel_sseu_status(m, gt);
279 }
280 DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(sseu_status);
281 
282 static int sseu_topology_show(struct seq_file *m, void *unused)
283 {
284 	struct intel_gt *gt = m->private;
285 	struct drm_printer p = drm_seq_file_printer(m);
286 
287 	intel_sseu_print_topology(gt->i915, &gt->info.sseu, &p);
288 
289 	return 0;
290 }
291 DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(sseu_topology);
292 
293 void intel_sseu_debugfs_register(struct intel_gt *gt, struct dentry *root)
294 {
295 	static const struct intel_gt_debugfs_file files[] = {
296 		{ "sseu_status", &sseu_status_fops, NULL },
297 		{ "sseu_topology", &sseu_topology_fops, NULL },
298 	};
299 
300 	intel_gt_debugfs_register_files(root, files, ARRAY_SIZE(files), gt);
301 }
302