| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301 |
- // SPDX-License-Identifier: MIT
- /*
- * Copyright © 2020 Intel Corporation
- */
- #include <linux/bitmap.h>
- #include <linux/string_helpers.h>
- #include <drm/drm_print.h>
- #include "i915_drv.h"
- #include "intel_gt_debugfs.h"
- #include "intel_gt_regs.h"
- #include "intel_sseu_debugfs.h"
- static void cherryview_sseu_device_status(struct intel_gt *gt,
- struct sseu_dev_info *sseu)
- {
- #define SS_MAX 2
- struct intel_uncore *uncore = gt->uncore;
- const int ss_max = SS_MAX;
- u32 sig1[SS_MAX], sig2[SS_MAX];
- int ss;
- sig1[0] = intel_uncore_read(uncore, CHV_POWER_SS0_SIG1);
- sig1[1] = intel_uncore_read(uncore, CHV_POWER_SS1_SIG1);
- sig2[0] = intel_uncore_read(uncore, CHV_POWER_SS0_SIG2);
- sig2[1] = intel_uncore_read(uncore, CHV_POWER_SS1_SIG2);
- for (ss = 0; ss < ss_max; ss++) {
- unsigned int eu_cnt;
- if (sig1[ss] & CHV_SS_PG_ENABLE)
- /* skip disabled subslice */
- continue;
- sseu->slice_mask = BIT(0);
- sseu->subslice_mask.hsw[0] |= BIT(ss);
- eu_cnt = ((sig1[ss] & CHV_EU08_PG_ENABLE) ? 0 : 2) +
- ((sig1[ss] & CHV_EU19_PG_ENABLE) ? 0 : 2) +
- ((sig1[ss] & CHV_EU210_PG_ENABLE) ? 0 : 2) +
- ((sig2[ss] & CHV_EU311_PG_ENABLE) ? 0 : 2);
- sseu->eu_total += eu_cnt;
- sseu->eu_per_subslice = max_t(unsigned int,
- sseu->eu_per_subslice, eu_cnt);
- }
- #undef SS_MAX
- }
- static void gen11_sseu_device_status(struct intel_gt *gt,
- struct sseu_dev_info *sseu)
- {
- #define SS_MAX 8
- struct intel_uncore *uncore = gt->uncore;
- const struct intel_gt_info *info = >->info;
- u32 s_reg[SS_MAX], eu_reg[2 * SS_MAX], eu_mask[2];
- int s, ss;
- for (s = 0; s < info->sseu.max_slices; s++) {
- /*
- * FIXME: Valid SS Mask respects the spec and read
- * only valid bits for those registers, excluding reserved
- * although this seems wrong because it would leave many
- * subslices without ACK.
- */
- s_reg[s] = intel_uncore_read(uncore, GEN10_SLICE_PGCTL_ACK(s)) &
- GEN10_PGCTL_VALID_SS_MASK(s);
- eu_reg[2 * s] = intel_uncore_read(uncore,
- GEN10_SS01_EU_PGCTL_ACK(s));
- eu_reg[2 * s + 1] = intel_uncore_read(uncore,
- GEN10_SS23_EU_PGCTL_ACK(s));
- }
- eu_mask[0] = GEN9_PGCTL_SSA_EU08_ACK |
- GEN9_PGCTL_SSA_EU19_ACK |
- GEN9_PGCTL_SSA_EU210_ACK |
- GEN9_PGCTL_SSA_EU311_ACK;
- eu_mask[1] = GEN9_PGCTL_SSB_EU08_ACK |
- GEN9_PGCTL_SSB_EU19_ACK |
- GEN9_PGCTL_SSB_EU210_ACK |
- GEN9_PGCTL_SSB_EU311_ACK;
- for (s = 0; s < info->sseu.max_slices; s++) {
- if ((s_reg[s] & GEN9_PGCTL_SLICE_ACK) == 0)
- /* skip disabled slice */
- continue;
- sseu->slice_mask |= BIT(s);
- sseu->subslice_mask.hsw[s] = info->sseu.subslice_mask.hsw[s];
- for (ss = 0; ss < info->sseu.max_subslices; ss++) {
- unsigned int eu_cnt;
- if (info->sseu.has_subslice_pg &&
- !(s_reg[s] & (GEN9_PGCTL_SS_ACK(ss))))
- /* skip disabled subslice */
- continue;
- eu_cnt = 2 * hweight32(eu_reg[2 * s + ss / 2] &
- eu_mask[ss % 2]);
- sseu->eu_total += eu_cnt;
- sseu->eu_per_subslice = max_t(unsigned int,
- sseu->eu_per_subslice,
- eu_cnt);
- }
- }
- #undef SS_MAX
- }
- static void gen9_sseu_device_status(struct intel_gt *gt,
- struct sseu_dev_info *sseu)
- {
- #define SS_MAX 3
- struct intel_uncore *uncore = gt->uncore;
- const struct intel_gt_info *info = >->info;
- u32 s_reg[SS_MAX], eu_reg[2 * SS_MAX], eu_mask[2];
- int s, ss;
- for (s = 0; s < info->sseu.max_slices; s++) {
- s_reg[s] = intel_uncore_read(uncore, GEN9_SLICE_PGCTL_ACK(s));
- eu_reg[2 * s] =
- intel_uncore_read(uncore, GEN9_SS01_EU_PGCTL_ACK(s));
- eu_reg[2 * s + 1] =
- intel_uncore_read(uncore, GEN9_SS23_EU_PGCTL_ACK(s));
- }
- eu_mask[0] = GEN9_PGCTL_SSA_EU08_ACK |
- GEN9_PGCTL_SSA_EU19_ACK |
- GEN9_PGCTL_SSA_EU210_ACK |
- GEN9_PGCTL_SSA_EU311_ACK;
- eu_mask[1] = GEN9_PGCTL_SSB_EU08_ACK |
- GEN9_PGCTL_SSB_EU19_ACK |
- GEN9_PGCTL_SSB_EU210_ACK |
- GEN9_PGCTL_SSB_EU311_ACK;
- for (s = 0; s < info->sseu.max_slices; s++) {
- if ((s_reg[s] & GEN9_PGCTL_SLICE_ACK) == 0)
- /* skip disabled slice */
- continue;
- sseu->slice_mask |= BIT(s);
- if (IS_GEN9_BC(gt->i915))
- sseu->subslice_mask.hsw[s] = info->sseu.subslice_mask.hsw[s];
- for (ss = 0; ss < info->sseu.max_subslices; ss++) {
- unsigned int eu_cnt;
- if (IS_GEN9_LP(gt->i915)) {
- if (!(s_reg[s] & (GEN9_PGCTL_SS_ACK(ss))))
- /* skip disabled subslice */
- continue;
- sseu->subslice_mask.hsw[s] |= BIT(ss);
- }
- eu_cnt = eu_reg[2 * s + ss / 2] & eu_mask[ss % 2];
- eu_cnt = 2 * hweight32(eu_cnt);
- sseu->eu_total += eu_cnt;
- sseu->eu_per_subslice = max_t(unsigned int,
- sseu->eu_per_subslice,
- eu_cnt);
- }
- }
- #undef SS_MAX
- }
- static void bdw_sseu_device_status(struct intel_gt *gt,
- struct sseu_dev_info *sseu)
- {
- const struct intel_gt_info *info = >->info;
- u32 slice_info = intel_uncore_read(gt->uncore, GEN8_GT_SLICE_INFO);
- int s;
- sseu->slice_mask = slice_info & GEN8_LSLICESTAT_MASK;
- if (sseu->slice_mask) {
- sseu->eu_per_subslice = info->sseu.eu_per_subslice;
- for (s = 0; s < fls(sseu->slice_mask); s++)
- sseu->subslice_mask.hsw[s] = info->sseu.subslice_mask.hsw[s];
- sseu->eu_total = sseu->eu_per_subslice *
- intel_sseu_subslice_total(sseu);
- /* subtract fused off EU(s) from enabled slice(s) */
- for (s = 0; s < fls(sseu->slice_mask); s++) {
- u8 subslice_7eu = info->sseu.subslice_7eu[s];
- sseu->eu_total -= hweight8(subslice_7eu);
- }
- }
- }
- static void i915_print_sseu_info(struct seq_file *m,
- bool is_available_info,
- bool has_pooled_eu,
- const struct sseu_dev_info *sseu)
- {
- const char *type = is_available_info ? "Available" : "Enabled";
- seq_printf(m, " %s Slice Mask: %04x\n", type,
- sseu->slice_mask);
- seq_printf(m, " %s Slice Total: %u\n", type,
- hweight8(sseu->slice_mask));
- seq_printf(m, " %s Subslice Total: %u\n", type,
- intel_sseu_subslice_total(sseu));
- intel_sseu_print_ss_info(type, sseu, m);
- seq_printf(m, " %s EU Total: %u\n", type,
- sseu->eu_total);
- seq_printf(m, " %s EU Per Subslice: %u\n", type,
- sseu->eu_per_subslice);
- if (!is_available_info)
- return;
- seq_printf(m, " Has Pooled EU: %s\n", str_yes_no(has_pooled_eu));
- if (has_pooled_eu)
- seq_printf(m, " Min EU in pool: %u\n", sseu->min_eu_in_pool);
- seq_printf(m, " Has Slice Power Gating: %s\n",
- str_yes_no(sseu->has_slice_pg));
- seq_printf(m, " Has Subslice Power Gating: %s\n",
- str_yes_no(sseu->has_subslice_pg));
- seq_printf(m, " Has EU Power Gating: %s\n",
- str_yes_no(sseu->has_eu_pg));
- }
- /*
- * this is called from top-level debugfs as well, so we can't get the gt from
- * the seq_file.
- */
- int intel_sseu_status(struct seq_file *m, struct intel_gt *gt)
- {
- struct drm_i915_private *i915 = gt->i915;
- const struct intel_gt_info *info = >->info;
- struct sseu_dev_info *sseu;
- intel_wakeref_t wakeref;
- if (GRAPHICS_VER(i915) < 8)
- return -ENODEV;
- seq_puts(m, "SSEU Device Info\n");
- i915_print_sseu_info(m, true, HAS_POOLED_EU(i915), &info->sseu);
- seq_puts(m, "SSEU Device Status\n");
- sseu = kzalloc(sizeof(*sseu), GFP_KERNEL);
- if (!sseu)
- return -ENOMEM;
- intel_sseu_set_info(sseu, info->sseu.max_slices,
- info->sseu.max_subslices,
- info->sseu.max_eus_per_subslice);
- with_intel_runtime_pm(&i915->runtime_pm, wakeref) {
- if (IS_CHERRYVIEW(i915))
- cherryview_sseu_device_status(gt, sseu);
- else if (IS_BROADWELL(i915))
- bdw_sseu_device_status(gt, sseu);
- else if (GRAPHICS_VER(i915) == 9)
- gen9_sseu_device_status(gt, sseu);
- else if (GRAPHICS_VER(i915) >= 11)
- gen11_sseu_device_status(gt, sseu);
- }
- i915_print_sseu_info(m, false, HAS_POOLED_EU(i915), sseu);
- kfree(sseu);
- return 0;
- }
- static int sseu_status_show(struct seq_file *m, void *unused)
- {
- struct intel_gt *gt = m->private;
- return intel_sseu_status(m, gt);
- }
- DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(sseu_status);
- static int sseu_topology_show(struct seq_file *m, void *unused)
- {
- struct intel_gt *gt = m->private;
- struct drm_printer p = drm_seq_file_printer(m);
- intel_sseu_print_topology(gt->i915, >->info.sseu, &p);
- return 0;
- }
- DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(sseu_topology);
- void intel_sseu_debugfs_register(struct intel_gt *gt, struct dentry *root)
- {
- static const struct intel_gt_debugfs_file files[] = {
- { .name = "sseu_status", .fops = &sseu_status_fops },
- { .name = "sseu_topology", .fops = &sseu_topology_fops },
- };
- intel_gt_debugfs_register_files(root, files, ARRAY_SIZE(files), gt);
- }
|