Merge branch 'stable/for-linus-5.15' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / drivers / gpu / drm / i915 / gt / intel_sseu_debugfs.c
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
11 static 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
19 static 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
53 static void gen11_sseu_device_status(struct intel_gt *gt,
54                                      struct sseu_dev_info *sseu)
55 {
56 #define SS_MAX 8
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
113 static 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
176 static 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
202 static 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  */
244 int 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 (GRAPHICS_VER(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 (GRAPHICS_VER(i915) == 9)
269                         gen9_sseu_device_status(gt, &sseu);
270                 else if (GRAPHICS_VER(i915) >= 11)
271                         gen11_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
279 static 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 }
285 DEFINE_GT_DEBUGFS_ATTRIBUTE(sseu_status);
286
287 static 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 }
296 DEFINE_GT_DEBUGFS_ATTRIBUTE(rcs_topology);
297
298 void 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 }