linux/drivers/gpu/drm/i915/gt/intel_sseu_debugfs.c
<<
>>
Prefs
   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}
 307