File Index
Files and directories
Sign in
FILE

intel_sseu_debugfs.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/i915/gt/intel_sseu_debugfs.c C
  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
 17static 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
 51static 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
111static 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
170static 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
195static 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 */
233int 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
274static 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}
280DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(sseu_status);
281
282static 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}
291DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(sseu_topology);
292
293void 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}
~/ Read-only file preview.