intel_sseu_debugfs.c 8.2 KB

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