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