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