Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: MIT
0002 
0003 /*
0004  * Copyright © 2020 Intel Corporation
0005  */
0006 
0007 #include <linux/bitmap.h>
0008 #include <linux/string_helpers.h>
0009 
0010 #include "i915_drv.h"
0011 #include "intel_gt_debugfs.h"
0012 #include "intel_gt_regs.h"
0013 #include "intel_sseu_debugfs.h"
0014 
0015 static void cherryview_sseu_device_status(struct intel_gt *gt,
0016                       struct sseu_dev_info *sseu)
0017 {
0018 #define SS_MAX 2
0019     struct intel_uncore *uncore = gt->uncore;
0020     const int ss_max = SS_MAX;
0021     u32 sig1[SS_MAX], sig2[SS_MAX];
0022     int ss;
0023 
0024     sig1[0] = intel_uncore_read(uncore, CHV_POWER_SS0_SIG1);
0025     sig1[1] = intel_uncore_read(uncore, CHV_POWER_SS1_SIG1);
0026     sig2[0] = intel_uncore_read(uncore, CHV_POWER_SS0_SIG2);
0027     sig2[1] = intel_uncore_read(uncore, CHV_POWER_SS1_SIG2);
0028 
0029     for (ss = 0; ss < ss_max; ss++) {
0030         unsigned int eu_cnt;
0031 
0032         if (sig1[ss] & CHV_SS_PG_ENABLE)
0033             /* skip disabled subslice */
0034             continue;
0035 
0036         sseu->slice_mask = BIT(0);
0037         sseu->subslice_mask.hsw[0] |= BIT(ss);
0038         eu_cnt = ((sig1[ss] & CHV_EU08_PG_ENABLE) ? 0 : 2) +
0039              ((sig1[ss] & CHV_EU19_PG_ENABLE) ? 0 : 2) +
0040              ((sig1[ss] & CHV_EU210_PG_ENABLE) ? 0 : 2) +
0041              ((sig2[ss] & CHV_EU311_PG_ENABLE) ? 0 : 2);
0042         sseu->eu_total += eu_cnt;
0043         sseu->eu_per_subslice = max_t(unsigned int,
0044                           sseu->eu_per_subslice, eu_cnt);
0045     }
0046 #undef SS_MAX
0047 }
0048 
0049 static void gen11_sseu_device_status(struct intel_gt *gt,
0050                      struct sseu_dev_info *sseu)
0051 {
0052 #define SS_MAX 8
0053     struct intel_uncore *uncore = gt->uncore;
0054     const struct intel_gt_info *info = &gt->info;
0055     u32 s_reg[SS_MAX], eu_reg[2 * SS_MAX], eu_mask[2];
0056     int s, ss;
0057 
0058     for (s = 0; s < info->sseu.max_slices; s++) {
0059         /*
0060          * FIXME: Valid SS Mask respects the spec and read
0061          * only valid bits for those registers, excluding reserved
0062          * although this seems wrong because it would leave many
0063          * subslices without ACK.
0064          */
0065         s_reg[s] = intel_uncore_read(uncore, GEN10_SLICE_PGCTL_ACK(s)) &
0066             GEN10_PGCTL_VALID_SS_MASK(s);
0067         eu_reg[2 * s] = intel_uncore_read(uncore,
0068                           GEN10_SS01_EU_PGCTL_ACK(s));
0069         eu_reg[2 * s + 1] = intel_uncore_read(uncore,
0070                               GEN10_SS23_EU_PGCTL_ACK(s));
0071     }
0072 
0073     eu_mask[0] = GEN9_PGCTL_SSA_EU08_ACK |
0074              GEN9_PGCTL_SSA_EU19_ACK |
0075              GEN9_PGCTL_SSA_EU210_ACK |
0076              GEN9_PGCTL_SSA_EU311_ACK;
0077     eu_mask[1] = GEN9_PGCTL_SSB_EU08_ACK |
0078              GEN9_PGCTL_SSB_EU19_ACK |
0079              GEN9_PGCTL_SSB_EU210_ACK |
0080              GEN9_PGCTL_SSB_EU311_ACK;
0081 
0082     for (s = 0; s < info->sseu.max_slices; s++) {
0083         if ((s_reg[s] & GEN9_PGCTL_SLICE_ACK) == 0)
0084             /* skip disabled slice */
0085             continue;
0086 
0087         sseu->slice_mask |= BIT(s);
0088         sseu->subslice_mask.hsw[s] = info->sseu.subslice_mask.hsw[s];
0089 
0090         for (ss = 0; ss < info->sseu.max_subslices; ss++) {
0091             unsigned int eu_cnt;
0092 
0093             if (info->sseu.has_subslice_pg &&
0094                 !(s_reg[s] & (GEN9_PGCTL_SS_ACK(ss))))
0095                 /* skip disabled subslice */
0096                 continue;
0097 
0098             eu_cnt = 2 * hweight32(eu_reg[2 * s + ss / 2] &
0099                            eu_mask[ss % 2]);
0100             sseu->eu_total += eu_cnt;
0101             sseu->eu_per_subslice = max_t(unsigned int,
0102                               sseu->eu_per_subslice,
0103                               eu_cnt);
0104         }
0105     }
0106 #undef SS_MAX
0107 }
0108 
0109 static void gen9_sseu_device_status(struct intel_gt *gt,
0110                     struct sseu_dev_info *sseu)
0111 {
0112 #define SS_MAX 3
0113     struct intel_uncore *uncore = gt->uncore;
0114     const struct intel_gt_info *info = &gt->info;
0115     u32 s_reg[SS_MAX], eu_reg[2 * SS_MAX], eu_mask[2];
0116     int s, ss;
0117 
0118     for (s = 0; s < info->sseu.max_slices; s++) {
0119         s_reg[s] = intel_uncore_read(uncore, GEN9_SLICE_PGCTL_ACK(s));
0120         eu_reg[2 * s] =
0121             intel_uncore_read(uncore, GEN9_SS01_EU_PGCTL_ACK(s));
0122         eu_reg[2 * s + 1] =
0123             intel_uncore_read(uncore, GEN9_SS23_EU_PGCTL_ACK(s));
0124     }
0125 
0126     eu_mask[0] = GEN9_PGCTL_SSA_EU08_ACK |
0127              GEN9_PGCTL_SSA_EU19_ACK |
0128              GEN9_PGCTL_SSA_EU210_ACK |
0129              GEN9_PGCTL_SSA_EU311_ACK;
0130     eu_mask[1] = GEN9_PGCTL_SSB_EU08_ACK |
0131              GEN9_PGCTL_SSB_EU19_ACK |
0132              GEN9_PGCTL_SSB_EU210_ACK |
0133              GEN9_PGCTL_SSB_EU311_ACK;
0134 
0135     for (s = 0; s < info->sseu.max_slices; s++) {
0136         if ((s_reg[s] & GEN9_PGCTL_SLICE_ACK) == 0)
0137             /* skip disabled slice */
0138             continue;
0139 
0140         sseu->slice_mask |= BIT(s);
0141 
0142         if (IS_GEN9_BC(gt->i915))
0143             sseu->subslice_mask.hsw[s] = info->sseu.subslice_mask.hsw[s];
0144 
0145         for (ss = 0; ss < info->sseu.max_subslices; ss++) {
0146             unsigned int eu_cnt;
0147 
0148             if (IS_GEN9_LP(gt->i915)) {
0149                 if (!(s_reg[s] & (GEN9_PGCTL_SS_ACK(ss))))
0150                     /* skip disabled subslice */
0151                     continue;
0152 
0153                 sseu->subslice_mask.hsw[s] |= BIT(ss);
0154             }
0155 
0156             eu_cnt = eu_reg[2 * s + ss / 2] & eu_mask[ss % 2];
0157             eu_cnt = 2 * hweight32(eu_cnt);
0158 
0159             sseu->eu_total += eu_cnt;
0160             sseu->eu_per_subslice = max_t(unsigned int,
0161                               sseu->eu_per_subslice,
0162                               eu_cnt);
0163         }
0164     }
0165 #undef SS_MAX
0166 }
0167 
0168 static void bdw_sseu_device_status(struct intel_gt *gt,
0169                    struct sseu_dev_info *sseu)
0170 {
0171     const struct intel_gt_info *info = &gt->info;
0172     u32 slice_info = intel_uncore_read(gt->uncore, GEN8_GT_SLICE_INFO);
0173     int s;
0174 
0175     sseu->slice_mask = slice_info & GEN8_LSLICESTAT_MASK;
0176 
0177     if (sseu->slice_mask) {
0178         sseu->eu_per_subslice = info->sseu.eu_per_subslice;
0179         for (s = 0; s < fls(sseu->slice_mask); s++)
0180             sseu->subslice_mask.hsw[s] = info->sseu.subslice_mask.hsw[s];
0181         sseu->eu_total = sseu->eu_per_subslice *
0182                  intel_sseu_subslice_total(sseu);
0183 
0184         /* subtract fused off EU(s) from enabled slice(s) */
0185         for (s = 0; s < fls(sseu->slice_mask); s++) {
0186             u8 subslice_7eu = info->sseu.subslice_7eu[s];
0187 
0188             sseu->eu_total -= hweight8(subslice_7eu);
0189         }
0190     }
0191 }
0192 
0193 static void i915_print_sseu_info(struct seq_file *m,
0194                  bool is_available_info,
0195                  bool has_pooled_eu,
0196                  const struct sseu_dev_info *sseu)
0197 {
0198     const char *type = is_available_info ? "Available" : "Enabled";
0199 
0200     seq_printf(m, "  %s Slice Mask: %04x\n", type,
0201            sseu->slice_mask);
0202     seq_printf(m, "  %s Slice Total: %u\n", type,
0203            hweight8(sseu->slice_mask));
0204     seq_printf(m, "  %s Subslice Total: %u\n", type,
0205            intel_sseu_subslice_total(sseu));
0206     intel_sseu_print_ss_info(type, sseu, m);
0207     seq_printf(m, "  %s EU Total: %u\n", type,
0208            sseu->eu_total);
0209     seq_printf(m, "  %s EU Per Subslice: %u\n", type,
0210            sseu->eu_per_subslice);
0211 
0212     if (!is_available_info)
0213         return;
0214 
0215     seq_printf(m, "  Has Pooled EU: %s\n", str_yes_no(has_pooled_eu));
0216     if (has_pooled_eu)
0217         seq_printf(m, "  Min EU in pool: %u\n", sseu->min_eu_in_pool);
0218 
0219     seq_printf(m, "  Has Slice Power Gating: %s\n",
0220            str_yes_no(sseu->has_slice_pg));
0221     seq_printf(m, "  Has Subslice Power Gating: %s\n",
0222            str_yes_no(sseu->has_subslice_pg));
0223     seq_printf(m, "  Has EU Power Gating: %s\n",
0224            str_yes_no(sseu->has_eu_pg));
0225 }
0226 
0227 /*
0228  * this is called from top-level debugfs as well, so we can't get the gt from
0229  * the seq_file.
0230  */
0231 int intel_sseu_status(struct seq_file *m, struct intel_gt *gt)
0232 {
0233     struct drm_i915_private *i915 = gt->i915;
0234     const struct intel_gt_info *info = &gt->info;
0235     struct sseu_dev_info *sseu;
0236     intel_wakeref_t wakeref;
0237 
0238     if (GRAPHICS_VER(i915) < 8)
0239         return -ENODEV;
0240 
0241     seq_puts(m, "SSEU Device Info\n");
0242     i915_print_sseu_info(m, true, HAS_POOLED_EU(i915), &info->sseu);
0243 
0244     seq_puts(m, "SSEU Device Status\n");
0245 
0246     sseu = kzalloc(sizeof(*sseu), GFP_KERNEL);
0247     if (!sseu)
0248         return -ENOMEM;
0249 
0250     intel_sseu_set_info(sseu, info->sseu.max_slices,
0251                 info->sseu.max_subslices,
0252                 info->sseu.max_eus_per_subslice);
0253 
0254     with_intel_runtime_pm(&i915->runtime_pm, wakeref) {
0255         if (IS_CHERRYVIEW(i915))
0256             cherryview_sseu_device_status(gt, sseu);
0257         else if (IS_BROADWELL(i915))
0258             bdw_sseu_device_status(gt, sseu);
0259         else if (GRAPHICS_VER(i915) == 9)
0260             gen9_sseu_device_status(gt, sseu);
0261         else if (GRAPHICS_VER(i915) >= 11)
0262             gen11_sseu_device_status(gt, sseu);
0263     }
0264 
0265     i915_print_sseu_info(m, false, HAS_POOLED_EU(i915), sseu);
0266 
0267     kfree(sseu);
0268 
0269     return 0;
0270 }
0271 
0272 static int sseu_status_show(struct seq_file *m, void *unused)
0273 {
0274     struct intel_gt *gt = m->private;
0275 
0276     return intel_sseu_status(m, gt);
0277 }
0278 DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(sseu_status);
0279 
0280 static int sseu_topology_show(struct seq_file *m, void *unused)
0281 {
0282     struct intel_gt *gt = m->private;
0283     struct drm_printer p = drm_seq_file_printer(m);
0284 
0285     intel_sseu_print_topology(gt->i915, &gt->info.sseu, &p);
0286 
0287     return 0;
0288 }
0289 DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(sseu_topology);
0290 
0291 void intel_sseu_debugfs_register(struct intel_gt *gt, struct dentry *root)
0292 {
0293     static const struct intel_gt_debugfs_file files[] = {
0294         { "sseu_status", &sseu_status_fops, NULL },
0295         { "sseu_topology", &sseu_topology_fops, NULL },
0296     };
0297 
0298     intel_gt_debugfs_register_files(root, files, ARRAY_SIZE(files), gt);
0299 }