0001
0002
0003
0004
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
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 = >->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
0061
0062
0063
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
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
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 = >->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
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
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 = >->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
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
0229
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 = >->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, >->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 }