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