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