300 lines · c
1// SPDX-License-Identifier: MIT2 3/*4 * Copyright © 2020 Intel Corporation5 */6 7#include <linux/bitmap.h>8#include <linux/string_helpers.h>9 10#include "i915_drv.h"11#include "intel_gt_debugfs.h"12#include "intel_gt_regs.h"13#include "intel_sseu_debugfs.h"14 15static void cherryview_sseu_device_status(struct intel_gt *gt,16 struct sseu_dev_info *sseu)17{18#define SS_MAX 219 struct intel_uncore *uncore = gt->uncore;20 const int ss_max = SS_MAX;21 u32 sig1[SS_MAX], sig2[SS_MAX];22 int ss;23 24 sig1[0] = intel_uncore_read(uncore, CHV_POWER_SS0_SIG1);25 sig1[1] = intel_uncore_read(uncore, CHV_POWER_SS1_SIG1);26 sig2[0] = intel_uncore_read(uncore, CHV_POWER_SS0_SIG2);27 sig2[1] = intel_uncore_read(uncore, CHV_POWER_SS1_SIG2);28 29 for (ss = 0; ss < ss_max; ss++) {30 unsigned int eu_cnt;31 32 if (sig1[ss] & CHV_SS_PG_ENABLE)33 /* skip disabled subslice */34 continue;35 36 sseu->slice_mask = BIT(0);37 sseu->subslice_mask.hsw[0] |= BIT(ss);38 eu_cnt = ((sig1[ss] & CHV_EU08_PG_ENABLE) ? 0 : 2) +39 ((sig1[ss] & CHV_EU19_PG_ENABLE) ? 0 : 2) +40 ((sig1[ss] & CHV_EU210_PG_ENABLE) ? 0 : 2) +41 ((sig2[ss] & CHV_EU311_PG_ENABLE) ? 0 : 2);42 sseu->eu_total += eu_cnt;43 sseu->eu_per_subslice = max_t(unsigned int,44 sseu->eu_per_subslice, eu_cnt);45 }46#undef SS_MAX47}48 49static void gen11_sseu_device_status(struct intel_gt *gt,50 struct sseu_dev_info *sseu)51{52#define SS_MAX 853 struct intel_uncore *uncore = gt->uncore;54 const struct intel_gt_info *info = >->info;55 u32 s_reg[SS_MAX], eu_reg[2 * SS_MAX], eu_mask[2];56 int s, ss;57 58 for (s = 0; s < info->sseu.max_slices; s++) {59 /*60 * FIXME: Valid SS Mask respects the spec and read61 * only valid bits for those registers, excluding reserved62 * although this seems wrong because it would leave many63 * subslices without ACK.64 */65 s_reg[s] = intel_uncore_read(uncore, GEN10_SLICE_PGCTL_ACK(s)) &66 GEN10_PGCTL_VALID_SS_MASK(s);67 eu_reg[2 * s] = intel_uncore_read(uncore,68 GEN10_SS01_EU_PGCTL_ACK(s));69 eu_reg[2 * s + 1] = intel_uncore_read(uncore,70 GEN10_SS23_EU_PGCTL_ACK(s));71 }72 73 eu_mask[0] = GEN9_PGCTL_SSA_EU08_ACK |74 GEN9_PGCTL_SSA_EU19_ACK |75 GEN9_PGCTL_SSA_EU210_ACK |76 GEN9_PGCTL_SSA_EU311_ACK;77 eu_mask[1] = GEN9_PGCTL_SSB_EU08_ACK |78 GEN9_PGCTL_SSB_EU19_ACK |79 GEN9_PGCTL_SSB_EU210_ACK |80 GEN9_PGCTL_SSB_EU311_ACK;81 82 for (s = 0; s < info->sseu.max_slices; s++) {83 if ((s_reg[s] & GEN9_PGCTL_SLICE_ACK) == 0)84 /* skip disabled slice */85 continue;86 87 sseu->slice_mask |= BIT(s);88 sseu->subslice_mask.hsw[s] = info->sseu.subslice_mask.hsw[s];89 90 for (ss = 0; ss < info->sseu.max_subslices; ss++) {91 unsigned int eu_cnt;92 93 if (info->sseu.has_subslice_pg &&94 !(s_reg[s] & (GEN9_PGCTL_SS_ACK(ss))))95 /* skip disabled subslice */96 continue;97 98 eu_cnt = 2 * hweight32(eu_reg[2 * s + ss / 2] &99 eu_mask[ss % 2]);100 sseu->eu_total += eu_cnt;101 sseu->eu_per_subslice = max_t(unsigned int,102 sseu->eu_per_subslice,103 eu_cnt);104 }105 }106#undef SS_MAX107}108 109static void gen9_sseu_device_status(struct intel_gt *gt,110 struct sseu_dev_info *sseu)111{112#define SS_MAX 3113 struct intel_uncore *uncore = gt->uncore;114 const struct intel_gt_info *info = >->info;115 u32 s_reg[SS_MAX], eu_reg[2 * SS_MAX], eu_mask[2];116 int s, ss;117 118 for (s = 0; s < info->sseu.max_slices; s++) {119 s_reg[s] = intel_uncore_read(uncore, GEN9_SLICE_PGCTL_ACK(s));120 eu_reg[2 * s] =121 intel_uncore_read(uncore, GEN9_SS01_EU_PGCTL_ACK(s));122 eu_reg[2 * s + 1] =123 intel_uncore_read(uncore, GEN9_SS23_EU_PGCTL_ACK(s));124 }125 126 eu_mask[0] = GEN9_PGCTL_SSA_EU08_ACK |127 GEN9_PGCTL_SSA_EU19_ACK |128 GEN9_PGCTL_SSA_EU210_ACK |129 GEN9_PGCTL_SSA_EU311_ACK;130 eu_mask[1] = GEN9_PGCTL_SSB_EU08_ACK |131 GEN9_PGCTL_SSB_EU19_ACK |132 GEN9_PGCTL_SSB_EU210_ACK |133 GEN9_PGCTL_SSB_EU311_ACK;134 135 for (s = 0; s < info->sseu.max_slices; s++) {136 if ((s_reg[s] & GEN9_PGCTL_SLICE_ACK) == 0)137 /* skip disabled slice */138 continue;139 140 sseu->slice_mask |= BIT(s);141 142 if (IS_GEN9_BC(gt->i915))143 sseu->subslice_mask.hsw[s] = info->sseu.subslice_mask.hsw[s];144 145 for (ss = 0; ss < info->sseu.max_subslices; ss++) {146 unsigned int eu_cnt;147 148 if (IS_GEN9_LP(gt->i915)) {149 if (!(s_reg[s] & (GEN9_PGCTL_SS_ACK(ss))))150 /* skip disabled subslice */151 continue;152 153 sseu->subslice_mask.hsw[s] |= BIT(ss);154 }155 156 eu_cnt = eu_reg[2 * s + ss / 2] & eu_mask[ss % 2];157 eu_cnt = 2 * hweight32(eu_cnt);158 159 sseu->eu_total += eu_cnt;160 sseu->eu_per_subslice = max_t(unsigned int,161 sseu->eu_per_subslice,162 eu_cnt);163 }164 }165#undef SS_MAX166}167 168static void bdw_sseu_device_status(struct intel_gt *gt,169 struct sseu_dev_info *sseu)170{171 const struct intel_gt_info *info = >->info;172 u32 slice_info = intel_uncore_read(gt->uncore, GEN8_GT_SLICE_INFO);173 int s;174 175 sseu->slice_mask = slice_info & GEN8_LSLICESTAT_MASK;176 177 if (sseu->slice_mask) {178 sseu->eu_per_subslice = info->sseu.eu_per_subslice;179 for (s = 0; s < fls(sseu->slice_mask); s++)180 sseu->subslice_mask.hsw[s] = info->sseu.subslice_mask.hsw[s];181 sseu->eu_total = sseu->eu_per_subslice *182 intel_sseu_subslice_total(sseu);183 184 /* subtract fused off EU(s) from enabled slice(s) */185 for (s = 0; s < fls(sseu->slice_mask); s++) {186 u8 subslice_7eu = info->sseu.subslice_7eu[s];187 188 sseu->eu_total -= hweight8(subslice_7eu);189 }190 }191}192 193static void i915_print_sseu_info(struct seq_file *m,194 bool is_available_info,195 bool has_pooled_eu,196 const struct sseu_dev_info *sseu)197{198 const char *type = is_available_info ? "Available" : "Enabled";199 200 seq_printf(m, " %s Slice Mask: %04x\n", type,201 sseu->slice_mask);202 seq_printf(m, " %s Slice Total: %u\n", type,203 hweight8(sseu->slice_mask));204 seq_printf(m, " %s Subslice Total: %u\n", type,205 intel_sseu_subslice_total(sseu));206 intel_sseu_print_ss_info(type, sseu, m);207 seq_printf(m, " %s EU Total: %u\n", type,208 sseu->eu_total);209 seq_printf(m, " %s EU Per Subslice: %u\n", type,210 sseu->eu_per_subslice);211 212 if (!is_available_info)213 return;214 215 seq_printf(m, " Has Pooled EU: %s\n", str_yes_no(has_pooled_eu));216 if (has_pooled_eu)217 seq_printf(m, " Min EU in pool: %u\n", sseu->min_eu_in_pool);218 219 seq_printf(m, " Has Slice Power Gating: %s\n",220 str_yes_no(sseu->has_slice_pg));221 seq_printf(m, " Has Subslice Power Gating: %s\n",222 str_yes_no(sseu->has_subslice_pg));223 seq_printf(m, " Has EU Power Gating: %s\n",224 str_yes_no(sseu->has_eu_pg));225}226 227/*228 * this is called from top-level debugfs as well, so we can't get the gt from229 * the seq_file.230 */231int intel_sseu_status(struct seq_file *m, struct intel_gt *gt)232{233 struct drm_i915_private *i915 = gt->i915;234 const struct intel_gt_info *info = >->info;235 struct sseu_dev_info *sseu;236 intel_wakeref_t wakeref;237 238 if (GRAPHICS_VER(i915) < 8)239 return -ENODEV;240 241 seq_puts(m, "SSEU Device Info\n");242 i915_print_sseu_info(m, true, HAS_POOLED_EU(i915), &info->sseu);243 244 seq_puts(m, "SSEU Device Status\n");245 246 sseu = kzalloc(sizeof(*sseu), GFP_KERNEL);247 if (!sseu)248 return -ENOMEM;249 250 intel_sseu_set_info(sseu, info->sseu.max_slices,251 info->sseu.max_subslices,252 info->sseu.max_eus_per_subslice);253 254 with_intel_runtime_pm(&i915->runtime_pm, wakeref) {255 if (IS_CHERRYVIEW(i915))256 cherryview_sseu_device_status(gt, sseu);257 else if (IS_BROADWELL(i915))258 bdw_sseu_device_status(gt, sseu);259 else if (GRAPHICS_VER(i915) == 9)260 gen9_sseu_device_status(gt, sseu);261 else if (GRAPHICS_VER(i915) >= 11)262 gen11_sseu_device_status(gt, sseu);263 }264 265 i915_print_sseu_info(m, false, HAS_POOLED_EU(i915), sseu);266 267 kfree(sseu);268 269 return 0;270}271 272static int sseu_status_show(struct seq_file *m, void *unused)273{274 struct intel_gt *gt = m->private;275 276 return intel_sseu_status(m, gt);277}278DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(sseu_status);279 280static int sseu_topology_show(struct seq_file *m, void *unused)281{282 struct intel_gt *gt = m->private;283 struct drm_printer p = drm_seq_file_printer(m);284 285 intel_sseu_print_topology(gt->i915, >->info.sseu, &p);286 287 return 0;288}289DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(sseu_topology);290 291void intel_sseu_debugfs_register(struct intel_gt *gt, struct dentry *root)292{293 static const struct intel_gt_debugfs_file files[] = {294 { "sseu_status", &sseu_status_fops, NULL },295 { "sseu_topology", &sseu_topology_fops, NULL },296 };297 298 intel_gt_debugfs_register_files(root, files, ARRAY_SIZE(files), gt);299}300