]> Git Repo - J-linux.git/blob - drivers/gpu/drm/i915/gt/intel_sseu.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / gpu / drm / i915 / gt / intel_sseu.c
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2019 Intel Corporation
4  */
5
6 #include <linux/string_helpers.h>
7
8 #include "i915_drv.h"
9 #include "i915_perf_types.h"
10 #include "intel_engine_regs.h"
11 #include "intel_gt_regs.h"
12 #include "intel_sseu.h"
13
14 void intel_sseu_set_info(struct sseu_dev_info *sseu, u8 max_slices,
15                          u8 max_subslices, u8 max_eus_per_subslice)
16 {
17         sseu->max_slices = max_slices;
18         sseu->max_subslices = max_subslices;
19         sseu->max_eus_per_subslice = max_eus_per_subslice;
20 }
21
22 unsigned int
23 intel_sseu_subslice_total(const struct sseu_dev_info *sseu)
24 {
25         unsigned int i, total = 0;
26
27         if (sseu->has_xehp_dss)
28                 return bitmap_weight(sseu->subslice_mask.xehp,
29                                      XEHP_BITMAP_BITS(sseu->subslice_mask));
30
31         for (i = 0; i < ARRAY_SIZE(sseu->subslice_mask.hsw); i++)
32                 total += hweight8(sseu->subslice_mask.hsw[i]);
33
34         return total;
35 }
36
37 unsigned int
38 intel_sseu_get_hsw_subslices(const struct sseu_dev_info *sseu, u8 slice)
39 {
40         WARN_ON(sseu->has_xehp_dss);
41         if (WARN_ON(slice >= sseu->max_slices))
42                 return 0;
43
44         return sseu->subslice_mask.hsw[slice];
45 }
46
47 static u16 sseu_get_eus(const struct sseu_dev_info *sseu, int slice,
48                         int subslice)
49 {
50         if (sseu->has_xehp_dss) {
51                 WARN_ON(slice > 0);
52                 return sseu->eu_mask.xehp[subslice];
53         } else {
54                 return sseu->eu_mask.hsw[slice][subslice];
55         }
56 }
57
58 static void sseu_set_eus(struct sseu_dev_info *sseu, int slice, int subslice,
59                          u16 eu_mask)
60 {
61         GEM_WARN_ON(eu_mask && __fls(eu_mask) >= sseu->max_eus_per_subslice);
62         if (sseu->has_xehp_dss) {
63                 GEM_WARN_ON(slice > 0);
64                 sseu->eu_mask.xehp[subslice] = eu_mask;
65         } else {
66                 sseu->eu_mask.hsw[slice][subslice] = eu_mask;
67         }
68 }
69
70 static u16 compute_eu_total(const struct sseu_dev_info *sseu)
71 {
72         int s, ss, total = 0;
73
74         for (s = 0; s < sseu->max_slices; s++)
75                 for (ss = 0; ss < sseu->max_subslices; ss++)
76                         if (sseu->has_xehp_dss)
77                                 total += hweight16(sseu->eu_mask.xehp[ss]);
78                         else
79                                 total += hweight16(sseu->eu_mask.hsw[s][ss]);
80
81         return total;
82 }
83
84 /**
85  * intel_sseu_copy_eumask_to_user - Copy EU mask into a userspace buffer
86  * @to: Pointer to userspace buffer to copy to
87  * @sseu: SSEU structure containing EU mask to copy
88  *
89  * Copies the EU mask to a userspace buffer in the format expected by
90  * the query ioctl's topology queries.
91  *
92  * Returns the result of the copy_to_user() operation.
93  */
94 int intel_sseu_copy_eumask_to_user(void __user *to,
95                                    const struct sseu_dev_info *sseu)
96 {
97         u8 eu_mask[GEN_SS_MASK_SIZE * GEN_MAX_EU_STRIDE] = {};
98         int eu_stride = GEN_SSEU_STRIDE(sseu->max_eus_per_subslice);
99         int len = sseu->max_slices * sseu->max_subslices * eu_stride;
100         int s, ss, i;
101
102         for (s = 0; s < sseu->max_slices; s++) {
103                 for (ss = 0; ss < sseu->max_subslices; ss++) {
104                         int uapi_offset =
105                                 s * sseu->max_subslices * eu_stride +
106                                 ss * eu_stride;
107                         u16 mask = sseu_get_eus(sseu, s, ss);
108
109                         for (i = 0; i < eu_stride; i++)
110                                 eu_mask[uapi_offset + i] =
111                                         (mask >> (BITS_PER_BYTE * i)) & 0xff;
112                 }
113         }
114
115         return copy_to_user(to, eu_mask, len);
116 }
117
118 /**
119  * intel_sseu_copy_ssmask_to_user - Copy subslice mask into a userspace buffer
120  * @to: Pointer to userspace buffer to copy to
121  * @sseu: SSEU structure containing subslice mask to copy
122  *
123  * Copies the subslice mask to a userspace buffer in the format expected by
124  * the query ioctl's topology queries.
125  *
126  * Returns the result of the copy_to_user() operation.
127  */
128 int intel_sseu_copy_ssmask_to_user(void __user *to,
129                                    const struct sseu_dev_info *sseu)
130 {
131         u8 ss_mask[GEN_SS_MASK_SIZE] = {};
132         int ss_stride = GEN_SSEU_STRIDE(sseu->max_subslices);
133         int len = sseu->max_slices * ss_stride;
134         int s, ss, i;
135
136         for (s = 0; s < sseu->max_slices; s++) {
137                 for (ss = 0; ss < sseu->max_subslices; ss++) {
138                         i = s * ss_stride * BITS_PER_BYTE + ss;
139
140                         if (!intel_sseu_has_subslice(sseu, s, ss))
141                                 continue;
142
143                         ss_mask[i / BITS_PER_BYTE] |= BIT(i % BITS_PER_BYTE);
144                 }
145         }
146
147         return copy_to_user(to, ss_mask, len);
148 }
149
150 static void gen11_compute_sseu_info(struct sseu_dev_info *sseu,
151                                     u32 ss_en, u16 eu_en)
152 {
153         u32 valid_ss_mask = GENMASK(sseu->max_subslices - 1, 0);
154         int ss;
155
156         sseu->slice_mask |= BIT(0);
157         sseu->subslice_mask.hsw[0] = ss_en & valid_ss_mask;
158
159         for (ss = 0; ss < sseu->max_subslices; ss++)
160                 if (intel_sseu_has_subslice(sseu, 0, ss))
161                         sseu_set_eus(sseu, 0, ss, eu_en);
162
163         sseu->eu_per_subslice = hweight16(eu_en);
164         sseu->eu_total = compute_eu_total(sseu);
165 }
166
167 static void xehp_compute_sseu_info(struct sseu_dev_info *sseu,
168                                    u16 eu_en)
169 {
170         int ss;
171
172         sseu->slice_mask |= BIT(0);
173
174         bitmap_or(sseu->subslice_mask.xehp,
175                   sseu->compute_subslice_mask.xehp,
176                   sseu->geometry_subslice_mask.xehp,
177                   XEHP_BITMAP_BITS(sseu->subslice_mask));
178
179         for (ss = 0; ss < sseu->max_subslices; ss++)
180                 if (intel_sseu_has_subslice(sseu, 0, ss))
181                         sseu_set_eus(sseu, 0, ss, eu_en);
182
183         sseu->eu_per_subslice = hweight16(eu_en);
184         sseu->eu_total = compute_eu_total(sseu);
185 }
186
187 static void
188 xehp_load_dss_mask(struct intel_uncore *uncore,
189                    intel_sseu_ss_mask_t *ssmask,
190                    int numregs,
191                    ...)
192 {
193         va_list argp;
194         u32 fuse_val[I915_MAX_SS_FUSE_REGS] = {};
195         int i;
196
197         if (WARN_ON(numregs > I915_MAX_SS_FUSE_REGS))
198                 numregs = I915_MAX_SS_FUSE_REGS;
199
200         va_start(argp, numregs);
201         for (i = 0; i < numregs; i++)
202                 fuse_val[i] = intel_uncore_read(uncore, va_arg(argp, i915_reg_t));
203         va_end(argp);
204
205         bitmap_from_arr32(ssmask->xehp, fuse_val, numregs * 32);
206 }
207
208 static void xehp_sseu_info_init(struct intel_gt *gt)
209 {
210         struct sseu_dev_info *sseu = &gt->info.sseu;
211         struct intel_uncore *uncore = gt->uncore;
212         u16 eu_en = 0;
213         u8 eu_en_fuse;
214         int num_compute_regs, num_geometry_regs;
215         int eu;
216
217         num_geometry_regs = 1;
218         num_compute_regs = 1;
219
220         /*
221          * The concept of slice has been removed in Xe_HP.  To be compatible
222          * with prior generations, assume a single slice across the entire
223          * device. Then calculate out the DSS for each workload type within
224          * that software slice.
225          */
226         intel_sseu_set_info(sseu, 1,
227                             32 * max(num_geometry_regs, num_compute_regs),
228                             HAS_ONE_EU_PER_FUSE_BIT(gt->i915) ? 8 : 16);
229         sseu->has_xehp_dss = 1;
230
231         xehp_load_dss_mask(uncore, &sseu->geometry_subslice_mask,
232                            num_geometry_regs,
233                            GEN12_GT_GEOMETRY_DSS_ENABLE);
234         xehp_load_dss_mask(uncore, &sseu->compute_subslice_mask,
235                            num_compute_regs,
236                            GEN12_GT_COMPUTE_DSS_ENABLE,
237                            XEHPC_GT_COMPUTE_DSS_ENABLE_EXT);
238
239         eu_en_fuse = intel_uncore_read(uncore, XEHP_EU_ENABLE) & XEHP_EU_ENA_MASK;
240
241         if (HAS_ONE_EU_PER_FUSE_BIT(gt->i915))
242                 eu_en = eu_en_fuse;
243         else
244                 for (eu = 0; eu < sseu->max_eus_per_subslice / 2; eu++)
245                         if (eu_en_fuse & BIT(eu))
246                                 eu_en |= BIT(eu * 2) | BIT(eu * 2 + 1);
247
248         xehp_compute_sseu_info(sseu, eu_en);
249 }
250
251 static void gen12_sseu_info_init(struct intel_gt *gt)
252 {
253         struct sseu_dev_info *sseu = &gt->info.sseu;
254         struct intel_uncore *uncore = gt->uncore;
255         u32 g_dss_en;
256         u16 eu_en = 0;
257         u8 eu_en_fuse;
258         u8 s_en;
259         int eu;
260
261         /*
262          * Gen12 has Dual-Subslices, which behave similarly to 2 gen11 SS.
263          * Instead of splitting these, provide userspace with an array
264          * of DSS to more closely represent the hardware resource.
265          */
266         intel_sseu_set_info(sseu, 1, 6, 16);
267
268         /*
269          * Although gen12 architecture supported multiple slices, TGL, RKL,
270          * DG1, and ADL only had a single slice.
271          */
272         s_en = intel_uncore_read(uncore, GEN11_GT_SLICE_ENABLE) &
273                 GEN11_GT_S_ENA_MASK;
274         drm_WARN_ON(&gt->i915->drm, s_en != 0x1);
275
276         g_dss_en = intel_uncore_read(uncore, GEN12_GT_GEOMETRY_DSS_ENABLE);
277
278         /* one bit per pair of EUs */
279         eu_en_fuse = ~(intel_uncore_read(uncore, GEN11_EU_DISABLE) &
280                        GEN11_EU_DIS_MASK);
281
282         for (eu = 0; eu < sseu->max_eus_per_subslice / 2; eu++)
283                 if (eu_en_fuse & BIT(eu))
284                         eu_en |= BIT(eu * 2) | BIT(eu * 2 + 1);
285
286         gen11_compute_sseu_info(sseu, g_dss_en, eu_en);
287
288         /* TGL only supports slice-level power gating */
289         sseu->has_slice_pg = 1;
290 }
291
292 static void gen11_sseu_info_init(struct intel_gt *gt)
293 {
294         struct sseu_dev_info *sseu = &gt->info.sseu;
295         struct intel_uncore *uncore = gt->uncore;
296         u32 ss_en;
297         u8 eu_en;
298         u8 s_en;
299
300         if (IS_JASPERLAKE(gt->i915) || IS_ELKHARTLAKE(gt->i915))
301                 intel_sseu_set_info(sseu, 1, 4, 8);
302         else
303                 intel_sseu_set_info(sseu, 1, 8, 8);
304
305         /*
306          * Although gen11 architecture supported multiple slices, ICL and
307          * EHL/JSL only had a single slice in practice.
308          */
309         s_en = intel_uncore_read(uncore, GEN11_GT_SLICE_ENABLE) &
310                 GEN11_GT_S_ENA_MASK;
311         drm_WARN_ON(&gt->i915->drm, s_en != 0x1);
312
313         ss_en = ~intel_uncore_read(uncore, GEN11_GT_SUBSLICE_DISABLE);
314
315         eu_en = ~(intel_uncore_read(uncore, GEN11_EU_DISABLE) &
316                   GEN11_EU_DIS_MASK);
317
318         gen11_compute_sseu_info(sseu, ss_en, eu_en);
319
320         /* ICL has no power gating restrictions. */
321         sseu->has_slice_pg = 1;
322         sseu->has_subslice_pg = 1;
323         sseu->has_eu_pg = 1;
324 }
325
326 static void cherryview_sseu_info_init(struct intel_gt *gt)
327 {
328         struct sseu_dev_info *sseu = &gt->info.sseu;
329         u32 fuse;
330
331         fuse = intel_uncore_read(gt->uncore, CHV_FUSE_GT);
332
333         sseu->slice_mask = BIT(0);
334         intel_sseu_set_info(sseu, 1, 2, 8);
335
336         if (!(fuse & CHV_FGT_DISABLE_SS0)) {
337                 u8 disabled_mask =
338                         ((fuse & CHV_FGT_EU_DIS_SS0_R0_MASK) >>
339                          CHV_FGT_EU_DIS_SS0_R0_SHIFT) |
340                         (((fuse & CHV_FGT_EU_DIS_SS0_R1_MASK) >>
341                           CHV_FGT_EU_DIS_SS0_R1_SHIFT) << 4);
342
343                 sseu->subslice_mask.hsw[0] |= BIT(0);
344                 sseu_set_eus(sseu, 0, 0, ~disabled_mask & 0xFF);
345         }
346
347         if (!(fuse & CHV_FGT_DISABLE_SS1)) {
348                 u8 disabled_mask =
349                         ((fuse & CHV_FGT_EU_DIS_SS1_R0_MASK) >>
350                          CHV_FGT_EU_DIS_SS1_R0_SHIFT) |
351                         (((fuse & CHV_FGT_EU_DIS_SS1_R1_MASK) >>
352                           CHV_FGT_EU_DIS_SS1_R1_SHIFT) << 4);
353
354                 sseu->subslice_mask.hsw[0] |= BIT(1);
355                 sseu_set_eus(sseu, 0, 1, ~disabled_mask & 0xFF);
356         }
357
358         sseu->eu_total = compute_eu_total(sseu);
359
360         /*
361          * CHV expected to always have a uniform distribution of EU
362          * across subslices.
363          */
364         sseu->eu_per_subslice = intel_sseu_subslice_total(sseu) ?
365                 sseu->eu_total /
366                 intel_sseu_subslice_total(sseu) :
367                 0;
368         /*
369          * CHV supports subslice power gating on devices with more than
370          * one subslice, and supports EU power gating on devices with
371          * more than one EU pair per subslice.
372          */
373         sseu->has_slice_pg = 0;
374         sseu->has_subslice_pg = intel_sseu_subslice_total(sseu) > 1;
375         sseu->has_eu_pg = (sseu->eu_per_subslice > 2);
376 }
377
378 static void gen9_sseu_info_init(struct intel_gt *gt)
379 {
380         struct drm_i915_private *i915 = gt->i915;
381         struct sseu_dev_info *sseu = &gt->info.sseu;
382         struct intel_uncore *uncore = gt->uncore;
383         u32 fuse2, eu_disable, subslice_mask;
384         const u8 eu_mask = 0xff;
385         int s, ss;
386
387         fuse2 = intel_uncore_read(uncore, GEN8_FUSE2);
388         sseu->slice_mask = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;
389
390         /* BXT has a single slice and at most 3 subslices. */
391         intel_sseu_set_info(sseu, IS_GEN9_LP(i915) ? 1 : 3,
392                             IS_GEN9_LP(i915) ? 3 : 4, 8);
393
394         /*
395          * The subslice disable field is global, i.e. it applies
396          * to each of the enabled slices.
397          */
398         subslice_mask = (1 << sseu->max_subslices) - 1;
399         subslice_mask &= ~((fuse2 & GEN9_F2_SS_DIS_MASK) >>
400                            GEN9_F2_SS_DIS_SHIFT);
401
402         /*
403          * Iterate through enabled slices and subslices to
404          * count the total enabled EU.
405          */
406         for (s = 0; s < sseu->max_slices; s++) {
407                 if (!(sseu->slice_mask & BIT(s)))
408                         /* skip disabled slice */
409                         continue;
410
411                 sseu->subslice_mask.hsw[s] = subslice_mask;
412
413                 eu_disable = intel_uncore_read(uncore, GEN9_EU_DISABLE(s));
414                 for (ss = 0; ss < sseu->max_subslices; ss++) {
415                         int eu_per_ss;
416                         u8 eu_disabled_mask;
417
418                         if (!intel_sseu_has_subslice(sseu, s, ss))
419                                 /* skip disabled subslice */
420                                 continue;
421
422                         eu_disabled_mask = (eu_disable >> (ss * 8)) & eu_mask;
423
424                         sseu_set_eus(sseu, s, ss, ~eu_disabled_mask & eu_mask);
425
426                         eu_per_ss = sseu->max_eus_per_subslice -
427                                 hweight8(eu_disabled_mask);
428
429                         /*
430                          * Record which subslice(s) has(have) 7 EUs. we
431                          * can tune the hash used to spread work among
432                          * subslices if they are unbalanced.
433                          */
434                         if (eu_per_ss == 7)
435                                 sseu->subslice_7eu[s] |= BIT(ss);
436                 }
437         }
438
439         sseu->eu_total = compute_eu_total(sseu);
440
441         /*
442          * SKL is expected to always have a uniform distribution
443          * of EU across subslices with the exception that any one
444          * EU in any one subslice may be fused off for die
445          * recovery. BXT is expected to be perfectly uniform in EU
446          * distribution.
447          */
448         sseu->eu_per_subslice =
449                 intel_sseu_subslice_total(sseu) ?
450                 DIV_ROUND_UP(sseu->eu_total, intel_sseu_subslice_total(sseu)) :
451                 0;
452
453         /*
454          * SKL+ supports slice power gating on devices with more than
455          * one slice, and supports EU power gating on devices with
456          * more than one EU pair per subslice. BXT+ supports subslice
457          * power gating on devices with more than one subslice, and
458          * supports EU power gating on devices with more than one EU
459          * pair per subslice.
460          */
461         sseu->has_slice_pg =
462                 !IS_GEN9_LP(i915) && hweight8(sseu->slice_mask) > 1;
463         sseu->has_subslice_pg =
464                 IS_GEN9_LP(i915) && intel_sseu_subslice_total(sseu) > 1;
465         sseu->has_eu_pg = sseu->eu_per_subslice > 2;
466
467         if (IS_GEN9_LP(i915)) {
468 #define IS_SS_DISABLED(ss)      (!(sseu->subslice_mask.hsw[0] & BIT(ss)))
469                 RUNTIME_INFO(i915)->has_pooled_eu = hweight8(sseu->subslice_mask.hsw[0]) == 3;
470
471                 sseu->min_eu_in_pool = 0;
472                 if (HAS_POOLED_EU(i915)) {
473                         if (IS_SS_DISABLED(2) || IS_SS_DISABLED(0))
474                                 sseu->min_eu_in_pool = 3;
475                         else if (IS_SS_DISABLED(1))
476                                 sseu->min_eu_in_pool = 6;
477                         else
478                                 sseu->min_eu_in_pool = 9;
479                 }
480 #undef IS_SS_DISABLED
481         }
482 }
483
484 static void bdw_sseu_info_init(struct intel_gt *gt)
485 {
486         struct sseu_dev_info *sseu = &gt->info.sseu;
487         struct intel_uncore *uncore = gt->uncore;
488         int s, ss;
489         u32 fuse2, subslice_mask, eu_disable[3]; /* s_max */
490         u32 eu_disable0, eu_disable1, eu_disable2;
491
492         fuse2 = intel_uncore_read(uncore, GEN8_FUSE2);
493         sseu->slice_mask = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;
494         intel_sseu_set_info(sseu, 3, 3, 8);
495
496         /*
497          * The subslice disable field is global, i.e. it applies
498          * to each of the enabled slices.
499          */
500         subslice_mask = GENMASK(sseu->max_subslices - 1, 0);
501         subslice_mask &= ~((fuse2 & GEN8_F2_SS_DIS_MASK) >>
502                            GEN8_F2_SS_DIS_SHIFT);
503         eu_disable0 = intel_uncore_read(uncore, GEN8_EU_DISABLE0);
504         eu_disable1 = intel_uncore_read(uncore, GEN8_EU_DISABLE1);
505         eu_disable2 = intel_uncore_read(uncore, GEN8_EU_DISABLE2);
506         eu_disable[0] = eu_disable0 & GEN8_EU_DIS0_S0_MASK;
507         eu_disable[1] = (eu_disable0 >> GEN8_EU_DIS0_S1_SHIFT) |
508                 ((eu_disable1 & GEN8_EU_DIS1_S1_MASK) <<
509                  (32 - GEN8_EU_DIS0_S1_SHIFT));
510         eu_disable[2] = (eu_disable1 >> GEN8_EU_DIS1_S2_SHIFT) |
511                 ((eu_disable2 & GEN8_EU_DIS2_S2_MASK) <<
512                  (32 - GEN8_EU_DIS1_S2_SHIFT));
513
514         /*
515          * Iterate through enabled slices and subslices to
516          * count the total enabled EU.
517          */
518         for (s = 0; s < sseu->max_slices; s++) {
519                 if (!(sseu->slice_mask & BIT(s)))
520                         /* skip disabled slice */
521                         continue;
522
523                 sseu->subslice_mask.hsw[s] = subslice_mask;
524
525                 for (ss = 0; ss < sseu->max_subslices; ss++) {
526                         u8 eu_disabled_mask;
527                         u32 n_disabled;
528
529                         if (!intel_sseu_has_subslice(sseu, s, ss))
530                                 /* skip disabled subslice */
531                                 continue;
532
533                         eu_disabled_mask =
534                                 eu_disable[s] >> (ss * sseu->max_eus_per_subslice);
535
536                         sseu_set_eus(sseu, s, ss, ~eu_disabled_mask & 0xFF);
537
538                         n_disabled = hweight8(eu_disabled_mask);
539
540                         /*
541                          * Record which subslices have 7 EUs.
542                          */
543                         if (sseu->max_eus_per_subslice - n_disabled == 7)
544                                 sseu->subslice_7eu[s] |= 1 << ss;
545                 }
546         }
547
548         sseu->eu_total = compute_eu_total(sseu);
549
550         /*
551          * BDW is expected to always have a uniform distribution of EU across
552          * subslices with the exception that any one EU in any one subslice may
553          * be fused off for die recovery.
554          */
555         sseu->eu_per_subslice =
556                 intel_sseu_subslice_total(sseu) ?
557                 DIV_ROUND_UP(sseu->eu_total, intel_sseu_subslice_total(sseu)) :
558                 0;
559
560         /*
561          * BDW supports slice power gating on devices with more than
562          * one slice.
563          */
564         sseu->has_slice_pg = hweight8(sseu->slice_mask) > 1;
565         sseu->has_subslice_pg = 0;
566         sseu->has_eu_pg = 0;
567 }
568
569 static void hsw_sseu_info_init(struct intel_gt *gt)
570 {
571         struct drm_i915_private *i915 = gt->i915;
572         struct sseu_dev_info *sseu = &gt->info.sseu;
573         u32 fuse1;
574         u8 subslice_mask = 0;
575         int s, ss;
576
577         /*
578          * There isn't a register to tell us how many slices/subslices. We
579          * work off the PCI-ids here.
580          */
581         switch (INTEL_INFO(i915)->gt) {
582         default:
583                 MISSING_CASE(INTEL_INFO(i915)->gt);
584                 fallthrough;
585         case 1:
586                 sseu->slice_mask = BIT(0);
587                 subslice_mask = BIT(0);
588                 break;
589         case 2:
590                 sseu->slice_mask = BIT(0);
591                 subslice_mask = BIT(0) | BIT(1);
592                 break;
593         case 3:
594                 sseu->slice_mask = BIT(0) | BIT(1);
595                 subslice_mask = BIT(0) | BIT(1);
596                 break;
597         }
598
599         fuse1 = intel_uncore_read(gt->uncore, HSW_PAVP_FUSE1);
600         switch (REG_FIELD_GET(HSW_F1_EU_DIS_MASK, fuse1)) {
601         default:
602                 MISSING_CASE(REG_FIELD_GET(HSW_F1_EU_DIS_MASK, fuse1));
603                 fallthrough;
604         case HSW_F1_EU_DIS_10EUS:
605                 sseu->eu_per_subslice = 10;
606                 break;
607         case HSW_F1_EU_DIS_8EUS:
608                 sseu->eu_per_subslice = 8;
609                 break;
610         case HSW_F1_EU_DIS_6EUS:
611                 sseu->eu_per_subslice = 6;
612                 break;
613         }
614
615         intel_sseu_set_info(sseu, hweight8(sseu->slice_mask),
616                             hweight8(subslice_mask),
617                             sseu->eu_per_subslice);
618
619         for (s = 0; s < sseu->max_slices; s++) {
620                 sseu->subslice_mask.hsw[s] = subslice_mask;
621
622                 for (ss = 0; ss < sseu->max_subslices; ss++) {
623                         sseu_set_eus(sseu, s, ss,
624                                      (1UL << sseu->eu_per_subslice) - 1);
625                 }
626         }
627
628         sseu->eu_total = compute_eu_total(sseu);
629
630         /* No powergating for you. */
631         sseu->has_slice_pg = 0;
632         sseu->has_subslice_pg = 0;
633         sseu->has_eu_pg = 0;
634 }
635
636 void intel_sseu_info_init(struct intel_gt *gt)
637 {
638         struct drm_i915_private *i915 = gt->i915;
639
640         if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 55))
641                 xehp_sseu_info_init(gt);
642         else if (GRAPHICS_VER(i915) >= 12)
643                 gen12_sseu_info_init(gt);
644         else if (GRAPHICS_VER(i915) >= 11)
645                 gen11_sseu_info_init(gt);
646         else if (GRAPHICS_VER(i915) >= 9)
647                 gen9_sseu_info_init(gt);
648         else if (IS_BROADWELL(i915))
649                 bdw_sseu_info_init(gt);
650         else if (IS_CHERRYVIEW(i915))
651                 cherryview_sseu_info_init(gt);
652         else if (IS_HASWELL(i915))
653                 hsw_sseu_info_init(gt);
654 }
655
656 u32 intel_sseu_make_rpcs(struct intel_gt *gt,
657                          const struct intel_sseu *req_sseu)
658 {
659         struct drm_i915_private *i915 = gt->i915;
660         const struct sseu_dev_info *sseu = &gt->info.sseu;
661         bool subslice_pg = sseu->has_subslice_pg;
662         u8 slices, subslices;
663         u32 rpcs = 0;
664
665         /*
666          * No explicit RPCS request is needed to ensure full
667          * slice/subslice/EU enablement prior to Gen9.
668          */
669         if (GRAPHICS_VER(i915) < 9)
670                 return 0;
671
672         /*
673          * If i915/perf is active, we want a stable powergating configuration
674          * on the system. Use the configuration pinned by i915/perf.
675          */
676         if (gt->perf.group && gt->perf.group[PERF_GROUP_OAG].exclusive_stream)
677                 req_sseu = &gt->perf.sseu;
678
679         slices = hweight8(req_sseu->slice_mask);
680         subslices = hweight8(req_sseu->subslice_mask);
681
682         /*
683          * Since the SScount bitfield in GEN8_R_PWR_CLK_STATE is only three bits
684          * wide and Icelake has up to eight subslices, specfial programming is
685          * needed in order to correctly enable all subslices.
686          *
687          * According to documentation software must consider the configuration
688          * as 2x4x8 and hardware will translate this to 1x8x8.
689          *
690          * Furthemore, even though SScount is three bits, maximum documented
691          * value for it is four. From this some rules/restrictions follow:
692          *
693          * 1.
694          * If enabled subslice count is greater than four, two whole slices must
695          * be enabled instead.
696          *
697          * 2.
698          * When more than one slice is enabled, hardware ignores the subslice
699          * count altogether.
700          *
701          * From these restrictions it follows that it is not possible to enable
702          * a count of subslices between the SScount maximum of four restriction,
703          * and the maximum available number on a particular SKU. Either all
704          * subslices are enabled, or a count between one and four on the first
705          * slice.
706          */
707         if (GRAPHICS_VER(i915) == 11 &&
708             slices == 1 &&
709             subslices > min_t(u8, 4, hweight8(sseu->subslice_mask.hsw[0]) / 2)) {
710                 GEM_BUG_ON(subslices & 1);
711
712                 subslice_pg = false;
713                 slices *= 2;
714         }
715
716         /*
717          * Starting in Gen9, render power gating can leave
718          * slice/subslice/EU in a partially enabled state. We
719          * must make an explicit request through RPCS for full
720          * enablement.
721          */
722         if (sseu->has_slice_pg) {
723                 u32 mask, val = slices;
724
725                 if (GRAPHICS_VER(i915) >= 11) {
726                         mask = GEN11_RPCS_S_CNT_MASK;
727                         val <<= GEN11_RPCS_S_CNT_SHIFT;
728                 } else {
729                         mask = GEN8_RPCS_S_CNT_MASK;
730                         val <<= GEN8_RPCS_S_CNT_SHIFT;
731                 }
732
733                 GEM_BUG_ON(val & ~mask);
734                 val &= mask;
735
736                 rpcs |= GEN8_RPCS_ENABLE | GEN8_RPCS_S_CNT_ENABLE | val;
737         }
738
739         if (subslice_pg) {
740                 u32 val = subslices;
741
742                 val <<= GEN8_RPCS_SS_CNT_SHIFT;
743
744                 GEM_BUG_ON(val & ~GEN8_RPCS_SS_CNT_MASK);
745                 val &= GEN8_RPCS_SS_CNT_MASK;
746
747                 rpcs |= GEN8_RPCS_ENABLE | GEN8_RPCS_SS_CNT_ENABLE | val;
748         }
749
750         if (sseu->has_eu_pg) {
751                 u32 val;
752
753                 val = req_sseu->min_eus_per_subslice << GEN8_RPCS_EU_MIN_SHIFT;
754                 GEM_BUG_ON(val & ~GEN8_RPCS_EU_MIN_MASK);
755                 val &= GEN8_RPCS_EU_MIN_MASK;
756
757                 rpcs |= val;
758
759                 val = req_sseu->max_eus_per_subslice << GEN8_RPCS_EU_MAX_SHIFT;
760                 GEM_BUG_ON(val & ~GEN8_RPCS_EU_MAX_MASK);
761                 val &= GEN8_RPCS_EU_MAX_MASK;
762
763                 rpcs |= val;
764
765                 rpcs |= GEN8_RPCS_ENABLE;
766         }
767
768         return rpcs;
769 }
770
771 void intel_sseu_dump(const struct sseu_dev_info *sseu, struct drm_printer *p)
772 {
773         int s;
774
775         if (sseu->has_xehp_dss) {
776                 drm_printf(p, "subslice total: %u\n",
777                            intel_sseu_subslice_total(sseu));
778                 drm_printf(p, "geometry dss mask=%*pb\n",
779                            XEHP_BITMAP_BITS(sseu->geometry_subslice_mask),
780                            sseu->geometry_subslice_mask.xehp);
781                 drm_printf(p, "compute dss mask=%*pb\n",
782                            XEHP_BITMAP_BITS(sseu->compute_subslice_mask),
783                            sseu->compute_subslice_mask.xehp);
784         } else {
785                 drm_printf(p, "slice total: %u, mask=%04x\n",
786                            hweight8(sseu->slice_mask), sseu->slice_mask);
787                 drm_printf(p, "subslice total: %u\n",
788                            intel_sseu_subslice_total(sseu));
789
790                 for (s = 0; s < sseu->max_slices; s++) {
791                         u8 ss_mask = sseu->subslice_mask.hsw[s];
792
793                         drm_printf(p, "slice%d: %u subslices, mask=%08x\n",
794                                    s, hweight8(ss_mask), ss_mask);
795                 }
796         }
797
798         drm_printf(p, "EU total: %u\n", sseu->eu_total);
799         drm_printf(p, "EU per subslice: %u\n", sseu->eu_per_subslice);
800         drm_printf(p, "has slice power gating: %s\n",
801                    str_yes_no(sseu->has_slice_pg));
802         drm_printf(p, "has subslice power gating: %s\n",
803                    str_yes_no(sseu->has_subslice_pg));
804         drm_printf(p, "has EU power gating: %s\n",
805                    str_yes_no(sseu->has_eu_pg));
806 }
807
808 static void sseu_print_hsw_topology(const struct sseu_dev_info *sseu,
809                                     struct drm_printer *p)
810 {
811         int s, ss;
812
813         for (s = 0; s < sseu->max_slices; s++) {
814                 u8 ss_mask = sseu->subslice_mask.hsw[s];
815
816                 drm_printf(p, "slice%d: %u subslice(s) (0x%08x):\n",
817                            s, hweight8(ss_mask), ss_mask);
818
819                 for (ss = 0; ss < sseu->max_subslices; ss++) {
820                         u16 enabled_eus = sseu_get_eus(sseu, s, ss);
821
822                         drm_printf(p, "\tsubslice%d: %u EUs (0x%hx)\n",
823                                    ss, hweight16(enabled_eus), enabled_eus);
824                 }
825         }
826 }
827
828 static void sseu_print_xehp_topology(const struct sseu_dev_info *sseu,
829                                      struct drm_printer *p)
830 {
831         int dss;
832
833         for (dss = 0; dss < sseu->max_subslices; dss++) {
834                 u16 enabled_eus = sseu_get_eus(sseu, 0, dss);
835
836                 drm_printf(p, "DSS_%02d: G:%3s C:%3s, %2u EUs (0x%04hx)\n", dss,
837                            str_yes_no(test_bit(dss, sseu->geometry_subslice_mask.xehp)),
838                            str_yes_no(test_bit(dss, sseu->compute_subslice_mask.xehp)),
839                            hweight16(enabled_eus), enabled_eus);
840         }
841 }
842
843 void intel_sseu_print_topology(struct drm_i915_private *i915,
844                                const struct sseu_dev_info *sseu,
845                                struct drm_printer *p)
846 {
847         if (sseu->max_slices == 0)
848                 drm_printf(p, "Unavailable\n");
849         else if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 55))
850                 sseu_print_xehp_topology(sseu, p);
851         else
852                 sseu_print_hsw_topology(sseu, p);
853 }
854
855 void intel_sseu_print_ss_info(const char *type,
856                               const struct sseu_dev_info *sseu,
857                               struct seq_file *m)
858 {
859         int s;
860
861         if (sseu->has_xehp_dss) {
862                 seq_printf(m, "  %s Geometry DSS: %u\n", type,
863                            bitmap_weight(sseu->geometry_subslice_mask.xehp,
864                                          XEHP_BITMAP_BITS(sseu->geometry_subslice_mask)));
865                 seq_printf(m, "  %s Compute DSS: %u\n", type,
866                            bitmap_weight(sseu->compute_subslice_mask.xehp,
867                                          XEHP_BITMAP_BITS(sseu->compute_subslice_mask)));
868         } else {
869                 for (s = 0; s < fls(sseu->slice_mask); s++)
870                         seq_printf(m, "  %s Slice%i subslices: %u\n", type,
871                                    s, hweight8(sseu->subslice_mask.hsw[s]));
872         }
873 }
874
875 u16 intel_slicemask_from_xehp_dssmask(intel_sseu_ss_mask_t dss_mask,
876                                       int dss_per_slice)
877 {
878         intel_sseu_ss_mask_t per_slice_mask = {};
879         unsigned long slice_mask = 0;
880         int i;
881
882         WARN_ON(DIV_ROUND_UP(XEHP_BITMAP_BITS(dss_mask), dss_per_slice) >
883                 8 * sizeof(slice_mask));
884
885         bitmap_fill(per_slice_mask.xehp, dss_per_slice);
886         for (i = 0; !bitmap_empty(dss_mask.xehp, XEHP_BITMAP_BITS(dss_mask)); i++) {
887                 if (bitmap_intersects(dss_mask.xehp, per_slice_mask.xehp, dss_per_slice))
888                         slice_mask |= BIT(i);
889
890                 bitmap_shift_right(dss_mask.xehp, dss_mask.xehp, dss_per_slice,
891                                    XEHP_BITMAP_BITS(dss_mask));
892         }
893
894         return slice_mask;
895 }
This page took 0.078147 seconds and 4 git commands to generate.