Linux Audio

Check our new training course

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