| 1 | // SPDX-License-Identifier: MIT | 
|---|
| 2 |  | 
|---|
| 3 | /* | 
|---|
| 4 | * Copyright © 2019 Intel Corporation | 
|---|
| 5 | */ | 
|---|
| 6 |  | 
|---|
| 7 | #include <linux/seq_file.h> | 
|---|
| 8 | #include <linux/string_helpers.h> | 
|---|
| 9 |  | 
|---|
| 10 | #include "i915_drv.h" | 
|---|
| 11 | #include "i915_reg.h" | 
|---|
| 12 | #include "intel_gt.h" | 
|---|
| 13 | #include "intel_gt_clock_utils.h" | 
|---|
| 14 | #include "intel_gt_debugfs.h" | 
|---|
| 15 | #include "intel_gt_pm.h" | 
|---|
| 16 | #include "intel_gt_pm_debugfs.h" | 
|---|
| 17 | #include "intel_gt_regs.h" | 
|---|
| 18 | #include "intel_llc.h" | 
|---|
| 19 | #include "intel_mchbar_regs.h" | 
|---|
| 20 | #include "intel_pcode.h" | 
|---|
| 21 | #include "intel_rc6.h" | 
|---|
| 22 | #include "intel_rps.h" | 
|---|
| 23 | #include "intel_runtime_pm.h" | 
|---|
| 24 | #include "intel_uncore.h" | 
|---|
| 25 | #include "vlv_iosf_sb.h" | 
|---|
| 26 |  | 
|---|
| 27 | void intel_gt_pm_debugfs_forcewake_user_open(struct intel_gt *gt) | 
|---|
| 28 | { | 
|---|
| 29 | atomic_inc(v: >->user_wakeref); | 
|---|
| 30 | intel_gt_pm_get_untracked(gt); | 
|---|
| 31 | if (GRAPHICS_VER(gt->i915) >= 6) | 
|---|
| 32 | intel_uncore_forcewake_user_get(uncore: gt->uncore); | 
|---|
| 33 | } | 
|---|
| 34 |  | 
|---|
| 35 | void intel_gt_pm_debugfs_forcewake_user_release(struct intel_gt *gt) | 
|---|
| 36 | { | 
|---|
| 37 | if (GRAPHICS_VER(gt->i915) >= 6) | 
|---|
| 38 | intel_uncore_forcewake_user_put(uncore: gt->uncore); | 
|---|
| 39 | intel_gt_pm_put_untracked(gt); | 
|---|
| 40 | atomic_dec(v: >->user_wakeref); | 
|---|
| 41 | } | 
|---|
| 42 |  | 
|---|
| 43 | static int forcewake_user_open(struct inode *inode, struct file *file) | 
|---|
| 44 | { | 
|---|
| 45 | struct intel_gt *gt = inode->i_private; | 
|---|
| 46 |  | 
|---|
| 47 | intel_gt_pm_debugfs_forcewake_user_open(gt); | 
|---|
| 48 |  | 
|---|
| 49 | return 0; | 
|---|
| 50 | } | 
|---|
| 51 |  | 
|---|
| 52 | static int forcewake_user_release(struct inode *inode, struct file *file) | 
|---|
| 53 | { | 
|---|
| 54 | struct intel_gt *gt = inode->i_private; | 
|---|
| 55 |  | 
|---|
| 56 | intel_gt_pm_debugfs_forcewake_user_release(gt); | 
|---|
| 57 |  | 
|---|
| 58 | return 0; | 
|---|
| 59 | } | 
|---|
| 60 |  | 
|---|
| 61 | static const struct file_operations forcewake_user_fops = { | 
|---|
| 62 | .owner = THIS_MODULE, | 
|---|
| 63 | .open = forcewake_user_open, | 
|---|
| 64 | .release = forcewake_user_release, | 
|---|
| 65 | }; | 
|---|
| 66 |  | 
|---|
| 67 | static int fw_domains_show(struct seq_file *m, void *data) | 
|---|
| 68 | { | 
|---|
| 69 | struct intel_gt *gt = m->private; | 
|---|
| 70 | struct intel_uncore *uncore = gt->uncore; | 
|---|
| 71 | struct intel_uncore_forcewake_domain *fw_domain; | 
|---|
| 72 | unsigned int tmp; | 
|---|
| 73 |  | 
|---|
| 74 | spin_lock_irq(lock: &uncore->lock); | 
|---|
| 75 |  | 
|---|
| 76 | seq_printf(m, fmt: "user.bypass_count = %u\n", | 
|---|
| 77 | uncore->user_forcewake_count); | 
|---|
| 78 |  | 
|---|
| 79 | for_each_fw_domain(fw_domain, uncore, tmp) | 
|---|
| 80 | seq_printf(m, fmt: "%s.wake_count = %u\n", | 
|---|
| 81 | intel_uncore_forcewake_domain_to_str(id: fw_domain->id), | 
|---|
| 82 | READ_ONCE(fw_domain->wake_count)); | 
|---|
| 83 |  | 
|---|
| 84 | spin_unlock_irq(lock: &uncore->lock); | 
|---|
| 85 |  | 
|---|
| 86 | return 0; | 
|---|
| 87 | } | 
|---|
| 88 | DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(fw_domains); | 
|---|
| 89 |  | 
|---|
| 90 | static int vlv_drpc(struct seq_file *m) | 
|---|
| 91 | { | 
|---|
| 92 | struct intel_gt *gt = m->private; | 
|---|
| 93 | struct intel_uncore *uncore = gt->uncore; | 
|---|
| 94 | u32 rcctl1, pw_status, mt_fwake_req; | 
|---|
| 95 |  | 
|---|
| 96 | mt_fwake_req = intel_uncore_read_fw(uncore, FORCEWAKE_MT); | 
|---|
| 97 | pw_status = intel_uncore_read(uncore, VLV_GTLC_PW_STATUS); | 
|---|
| 98 | rcctl1 = intel_uncore_read(uncore, GEN6_RC_CONTROL); | 
|---|
| 99 |  | 
|---|
| 100 | seq_printf(m, fmt: "RC6 Enabled: %s\n", | 
|---|
| 101 | str_yes_no(v: rcctl1 & (GEN7_RC_CTL_TO_MODE | | 
|---|
| 102 | GEN6_RC_CTL_EI_MODE(1)))); | 
|---|
| 103 | seq_printf(m, fmt: "Multi-threaded Forcewake Request: 0x%x\n", mt_fwake_req); | 
|---|
| 104 | seq_printf(m, fmt: "Render Power Well: %s\n", | 
|---|
| 105 | (pw_status & VLV_GTLC_PW_RENDER_STATUS_MASK) ? "Up": "Down"); | 
|---|
| 106 | seq_printf(m, fmt: "Media Power Well: %s\n", | 
|---|
| 107 | (pw_status & VLV_GTLC_PW_MEDIA_STATUS_MASK) ? "Up": "Down"); | 
|---|
| 108 |  | 
|---|
| 109 | intel_rc6_print_residency(m, title: "Render RC6 residency since boot:", id: INTEL_RC6_RES_RC6); | 
|---|
| 110 | intel_rc6_print_residency(m, title: "Media RC6 residency since boot:", id: INTEL_RC6_RES_VLV_MEDIA); | 
|---|
| 111 |  | 
|---|
| 112 | return fw_domains_show(m, NULL); | 
|---|
| 113 | } | 
|---|
| 114 |  | 
|---|
| 115 | static int gen6_drpc(struct seq_file *m) | 
|---|
| 116 | { | 
|---|
| 117 | struct intel_gt *gt = m->private; | 
|---|
| 118 | struct drm_i915_private *i915 = gt->i915; | 
|---|
| 119 | struct intel_uncore *uncore = gt->uncore; | 
|---|
| 120 | u32 gt_core_status, mt_fwake_req, rcctl1, rc6vids = 0; | 
|---|
| 121 | u32 gen9_powergate_enable = 0, gen9_powergate_status = 0; | 
|---|
| 122 |  | 
|---|
| 123 | mt_fwake_req = intel_uncore_read_fw(uncore, FORCEWAKE_MT); | 
|---|
| 124 | gt_core_status = intel_uncore_read_fw(uncore, GEN6_GT_CORE_STATUS); | 
|---|
| 125 |  | 
|---|
| 126 | rcctl1 = intel_uncore_read(uncore, GEN6_RC_CONTROL); | 
|---|
| 127 | if (GRAPHICS_VER(i915) >= 9) { | 
|---|
| 128 | gen9_powergate_enable = | 
|---|
| 129 | intel_uncore_read(uncore, GEN9_PG_ENABLE); | 
|---|
| 130 | gen9_powergate_status = | 
|---|
| 131 | intel_uncore_read(uncore, GEN9_PWRGT_DOMAIN_STATUS); | 
|---|
| 132 | } | 
|---|
| 133 |  | 
|---|
| 134 | if (GRAPHICS_VER(i915) <= 7) | 
|---|
| 135 | snb_pcode_read(uncore: gt->uncore, GEN6_PCODE_READ_RC6VIDS, val: &rc6vids, NULL); | 
|---|
| 136 |  | 
|---|
| 137 | seq_printf(m, fmt: "RC1e Enabled: %s\n", | 
|---|
| 138 | str_yes_no(v: rcctl1 & GEN6_RC_CTL_RC1e_ENABLE)); | 
|---|
| 139 | seq_printf(m, fmt: "RC6 Enabled: %s\n", | 
|---|
| 140 | str_yes_no(v: rcctl1 & GEN6_RC_CTL_RC6_ENABLE)); | 
|---|
| 141 | if (GRAPHICS_VER(i915) >= 9) { | 
|---|
| 142 | seq_printf(m, fmt: "Render Well Gating Enabled: %s\n", | 
|---|
| 143 | str_yes_no(v: gen9_powergate_enable & GEN9_RENDER_PG_ENABLE)); | 
|---|
| 144 | seq_printf(m, fmt: "Media Well Gating Enabled: %s\n", | 
|---|
| 145 | str_yes_no(v: gen9_powergate_enable & GEN9_MEDIA_PG_ENABLE)); | 
|---|
| 146 | } | 
|---|
| 147 | seq_printf(m, fmt: "Deep RC6 Enabled: %s\n", | 
|---|
| 148 | str_yes_no(v: rcctl1 & GEN6_RC_CTL_RC6p_ENABLE)); | 
|---|
| 149 | seq_printf(m, fmt: "Deepest RC6 Enabled: %s\n", | 
|---|
| 150 | str_yes_no(v: rcctl1 & GEN6_RC_CTL_RC6pp_ENABLE)); | 
|---|
| 151 | seq_puts(m, s: "Current RC state: "); | 
|---|
| 152 | switch (gt_core_status & GEN6_RCn_MASK) { | 
|---|
| 153 | case GEN6_RC0: | 
|---|
| 154 | if (gt_core_status & GEN6_CORE_CPD_STATE_MASK) | 
|---|
| 155 | seq_puts(m, s: "Core Power Down\n"); | 
|---|
| 156 | else | 
|---|
| 157 | seq_puts(m, s: "on\n"); | 
|---|
| 158 | break; | 
|---|
| 159 | case GEN6_RC3: | 
|---|
| 160 | seq_puts(m, s: "RC3\n"); | 
|---|
| 161 | break; | 
|---|
| 162 | case GEN6_RC6: | 
|---|
| 163 | seq_puts(m, s: "RC6\n"); | 
|---|
| 164 | break; | 
|---|
| 165 | case GEN6_RC7: | 
|---|
| 166 | seq_puts(m, s: "RC7\n"); | 
|---|
| 167 | break; | 
|---|
| 168 | default: | 
|---|
| 169 | seq_puts(m, s: "Unknown\n"); | 
|---|
| 170 | break; | 
|---|
| 171 | } | 
|---|
| 172 |  | 
|---|
| 173 | seq_printf(m, fmt: "Core Power Down: %s\n", | 
|---|
| 174 | str_yes_no(v: gt_core_status & GEN6_CORE_CPD_STATE_MASK)); | 
|---|
| 175 | seq_printf(m, fmt: "Multi-threaded Forcewake Request: 0x%x\n", mt_fwake_req); | 
|---|
| 176 | if (GRAPHICS_VER(i915) >= 9) { | 
|---|
| 177 | seq_printf(m, fmt: "Render Power Well: %s\n", | 
|---|
| 178 | (gen9_powergate_status & | 
|---|
| 179 | GEN9_PWRGT_RENDER_STATUS_MASK) ? "Up": "Down"); | 
|---|
| 180 | seq_printf(m, fmt: "Media Power Well: %s\n", | 
|---|
| 181 | (gen9_powergate_status & | 
|---|
| 182 | GEN9_PWRGT_MEDIA_STATUS_MASK) ? "Up": "Down"); | 
|---|
| 183 | } | 
|---|
| 184 |  | 
|---|
| 185 | /* Not exactly sure what this is */ | 
|---|
| 186 | intel_rc6_print_residency(m, title: "RC6 \"Locked to RPn\" residency since boot:", | 
|---|
| 187 | id: INTEL_RC6_RES_RC6_LOCKED); | 
|---|
| 188 | intel_rc6_print_residency(m, title: "RC6 residency since boot:", id: INTEL_RC6_RES_RC6); | 
|---|
| 189 | intel_rc6_print_residency(m, title: "RC6+ residency since boot:", id: INTEL_RC6_RES_RC6p); | 
|---|
| 190 | intel_rc6_print_residency(m, title: "RC6++ residency since boot:", id: INTEL_RC6_RES_RC6pp); | 
|---|
| 191 |  | 
|---|
| 192 | if (GRAPHICS_VER(i915) <= 7) { | 
|---|
| 193 | seq_printf(m, fmt: "RC6   voltage: %dmV\n", | 
|---|
| 194 | GEN6_DECODE_RC6_VID(((rc6vids >> 0) & 0xff))); | 
|---|
| 195 | seq_printf(m, fmt: "RC6+  voltage: %dmV\n", | 
|---|
| 196 | GEN6_DECODE_RC6_VID(((rc6vids >> 8) & 0xff))); | 
|---|
| 197 | seq_printf(m, fmt: "RC6++ voltage: %dmV\n", | 
|---|
| 198 | GEN6_DECODE_RC6_VID(((rc6vids >> 16) & 0xff))); | 
|---|
| 199 | } | 
|---|
| 200 |  | 
|---|
| 201 | return fw_domains_show(m, NULL); | 
|---|
| 202 | } | 
|---|
| 203 |  | 
|---|
| 204 | static int ilk_drpc(struct seq_file *m) | 
|---|
| 205 | { | 
|---|
| 206 | struct intel_gt *gt = m->private; | 
|---|
| 207 | struct intel_uncore *uncore = gt->uncore; | 
|---|
| 208 | u32 rgvmodectl, rstdbyctl; | 
|---|
| 209 | u16 crstandvid; | 
|---|
| 210 |  | 
|---|
| 211 | rgvmodectl = intel_uncore_read(uncore, MEMMODECTL); | 
|---|
| 212 | rstdbyctl = intel_uncore_read(uncore, RSTDBYCTL); | 
|---|
| 213 | crstandvid = intel_uncore_read16(uncore, CRSTANDVID); | 
|---|
| 214 |  | 
|---|
| 215 | seq_printf(m, fmt: "HD boost: %s\n", | 
|---|
| 216 | str_yes_no(v: rgvmodectl & MEMMODE_BOOST_EN)); | 
|---|
| 217 | seq_printf(m, fmt: "Boost freq: %d\n", | 
|---|
| 218 | (rgvmodectl & MEMMODE_BOOST_FREQ_MASK) >> | 
|---|
| 219 | MEMMODE_BOOST_FREQ_SHIFT); | 
|---|
| 220 | seq_printf(m, fmt: "HW control enabled: %s\n", | 
|---|
| 221 | str_yes_no(v: rgvmodectl & MEMMODE_HWIDLE_EN)); | 
|---|
| 222 | seq_printf(m, fmt: "SW control enabled: %s\n", | 
|---|
| 223 | str_yes_no(v: rgvmodectl & MEMMODE_SWMODE_EN)); | 
|---|
| 224 | seq_printf(m, fmt: "Gated voltage change: %s\n", | 
|---|
| 225 | str_yes_no(v: rgvmodectl & MEMMODE_RCLK_GATE)); | 
|---|
| 226 | seq_printf(m, fmt: "Starting frequency: P%d\n", | 
|---|
| 227 | (rgvmodectl & MEMMODE_FSTART_MASK) >> MEMMODE_FSTART_SHIFT); | 
|---|
| 228 | seq_printf(m, fmt: "Max P-state: P%d\n", | 
|---|
| 229 | (rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT); | 
|---|
| 230 | seq_printf(m, fmt: "Min P-state: P%d\n", (rgvmodectl & MEMMODE_FMIN_MASK)); | 
|---|
| 231 | seq_printf(m, fmt: "RS1 VID: %d\n", (crstandvid & 0x3f)); | 
|---|
| 232 | seq_printf(m, fmt: "RS2 VID: %d\n", ((crstandvid >> 8) & 0x3f)); | 
|---|
| 233 | seq_printf(m, fmt: "Render standby enabled: %s\n", | 
|---|
| 234 | str_yes_no(v: !(rstdbyctl & RCX_SW_EXIT))); | 
|---|
| 235 | seq_puts(m, s: "Current RS state: "); | 
|---|
| 236 | switch (rstdbyctl & RSX_STATUS_MASK) { | 
|---|
| 237 | case RSX_STATUS_ON: | 
|---|
| 238 | seq_puts(m, s: "on\n"); | 
|---|
| 239 | break; | 
|---|
| 240 | case RSX_STATUS_RC1: | 
|---|
| 241 | seq_puts(m, s: "RC1\n"); | 
|---|
| 242 | break; | 
|---|
| 243 | case RSX_STATUS_RC1E: | 
|---|
| 244 | seq_puts(m, s: "RC1E\n"); | 
|---|
| 245 | break; | 
|---|
| 246 | case RSX_STATUS_RS1: | 
|---|
| 247 | seq_puts(m, s: "RS1\n"); | 
|---|
| 248 | break; | 
|---|
| 249 | case RSX_STATUS_RS2: | 
|---|
| 250 | seq_puts(m, s: "RS2 (RC6)\n"); | 
|---|
| 251 | break; | 
|---|
| 252 | case RSX_STATUS_RS3: | 
|---|
| 253 | seq_puts(m, s: "RC3 (RC6+)\n"); | 
|---|
| 254 | break; | 
|---|
| 255 | default: | 
|---|
| 256 | seq_puts(m, s: "unknown\n"); | 
|---|
| 257 | break; | 
|---|
| 258 | } | 
|---|
| 259 |  | 
|---|
| 260 | return 0; | 
|---|
| 261 | } | 
|---|
| 262 |  | 
|---|
| 263 | static int mtl_drpc(struct seq_file *m) | 
|---|
| 264 | { | 
|---|
| 265 | struct intel_gt *gt = m->private; | 
|---|
| 266 | struct intel_uncore *uncore = gt->uncore; | 
|---|
| 267 | u32 gt_core_status, rcctl1, mt_fwake_req; | 
|---|
| 268 | u32 mtl_powergate_enable = 0, mtl_powergate_status = 0; | 
|---|
| 269 |  | 
|---|
| 270 | mt_fwake_req = intel_uncore_read_fw(uncore, FORCEWAKE_MT); | 
|---|
| 271 | gt_core_status = intel_uncore_read(uncore, MTL_MIRROR_TARGET_WP1); | 
|---|
| 272 |  | 
|---|
| 273 | rcctl1 = intel_uncore_read(uncore, GEN6_RC_CONTROL); | 
|---|
| 274 | mtl_powergate_enable = intel_uncore_read(uncore, GEN9_PG_ENABLE); | 
|---|
| 275 | mtl_powergate_status = intel_uncore_read(uncore, | 
|---|
| 276 | GEN9_PWRGT_DOMAIN_STATUS); | 
|---|
| 277 |  | 
|---|
| 278 | seq_printf(m, fmt: "RC6 Enabled: %s\n", | 
|---|
| 279 | str_yes_no(v: rcctl1 & GEN6_RC_CTL_RC6_ENABLE)); | 
|---|
| 280 | if (gt->type == GT_MEDIA) { | 
|---|
| 281 | seq_printf(m, fmt: "Media Well Gating Enabled: %s\n", | 
|---|
| 282 | str_yes_no(v: mtl_powergate_enable & GEN9_MEDIA_PG_ENABLE)); | 
|---|
| 283 | } else { | 
|---|
| 284 | seq_printf(m, fmt: "Render Well Gating Enabled: %s\n", | 
|---|
| 285 | str_yes_no(v: mtl_powergate_enable & GEN9_RENDER_PG_ENABLE)); | 
|---|
| 286 | } | 
|---|
| 287 |  | 
|---|
| 288 | seq_puts(m, s: "Current RC state: "); | 
|---|
| 289 | switch (REG_FIELD_GET(MTL_CC_MASK, gt_core_status)) { | 
|---|
| 290 | case MTL_CC0: | 
|---|
| 291 | seq_puts(m, s: "RC0\n"); | 
|---|
| 292 | break; | 
|---|
| 293 | case MTL_CC6: | 
|---|
| 294 | seq_puts(m, s: "RC6\n"); | 
|---|
| 295 | break; | 
|---|
| 296 | default: | 
|---|
| 297 | seq_puts(m, s: "Unknown\n"); | 
|---|
| 298 | break; | 
|---|
| 299 | } | 
|---|
| 300 |  | 
|---|
| 301 | seq_printf(m, fmt: "Multi-threaded Forcewake Request: 0x%x\n", mt_fwake_req); | 
|---|
| 302 | if (gt->type == GT_MEDIA) | 
|---|
| 303 | seq_printf(m, fmt: "Media Power Well: %s\n", | 
|---|
| 304 | (mtl_powergate_status & | 
|---|
| 305 | GEN9_PWRGT_MEDIA_STATUS_MASK) ? "Up": "Down"); | 
|---|
| 306 | else | 
|---|
| 307 | seq_printf(m, fmt: "Render Power Well: %s\n", | 
|---|
| 308 | (mtl_powergate_status & | 
|---|
| 309 | GEN9_PWRGT_RENDER_STATUS_MASK) ? "Up": "Down"); | 
|---|
| 310 |  | 
|---|
| 311 | /* Works for both render and media gt's */ | 
|---|
| 312 | intel_rc6_print_residency(m, title: "RC6 residency since boot:", id: INTEL_RC6_RES_RC6); | 
|---|
| 313 |  | 
|---|
| 314 | return fw_domains_show(m, NULL); | 
|---|
| 315 | } | 
|---|
| 316 |  | 
|---|
| 317 | static int drpc_show(struct seq_file *m, void *unused) | 
|---|
| 318 | { | 
|---|
| 319 | struct intel_gt *gt = m->private; | 
|---|
| 320 | struct drm_i915_private *i915 = gt->i915; | 
|---|
| 321 | intel_wakeref_t wakeref; | 
|---|
| 322 | int err = -ENODEV; | 
|---|
| 323 |  | 
|---|
| 324 | with_intel_runtime_pm(gt->uncore->rpm, wakeref) { | 
|---|
| 325 | if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 70)) | 
|---|
| 326 | err = mtl_drpc(m); | 
|---|
| 327 | else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) | 
|---|
| 328 | err = vlv_drpc(m); | 
|---|
| 329 | else if (GRAPHICS_VER(i915) >= 6) | 
|---|
| 330 | err = gen6_drpc(m); | 
|---|
| 331 | else | 
|---|
| 332 | err = ilk_drpc(m); | 
|---|
| 333 | } | 
|---|
| 334 |  | 
|---|
| 335 | return err; | 
|---|
| 336 | } | 
|---|
| 337 | DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(drpc); | 
|---|
| 338 |  | 
|---|
| 339 | void intel_gt_pm_frequency_dump(struct intel_gt *gt, struct drm_printer *p) | 
|---|
| 340 | { | 
|---|
| 341 | struct drm_i915_private *i915 = gt->i915; | 
|---|
| 342 | struct intel_uncore *uncore = gt->uncore; | 
|---|
| 343 | struct intel_rps *rps = >->rps; | 
|---|
| 344 | intel_wakeref_t wakeref; | 
|---|
| 345 |  | 
|---|
| 346 | wakeref = intel_runtime_pm_get(rpm: uncore->rpm); | 
|---|
| 347 |  | 
|---|
| 348 | if (GRAPHICS_VER(i915) == 5) { | 
|---|
| 349 | u16 rgvswctl = intel_uncore_read16(uncore, MEMSWCTL); | 
|---|
| 350 | u16 rgvstat = intel_uncore_read16(uncore, MEMSTAT_ILK); | 
|---|
| 351 |  | 
|---|
| 352 | drm_printf(p, f: "Requested P-state: %d\n", (rgvswctl >> 8) & 0xf); | 
|---|
| 353 | drm_printf(p, f: "Requested VID: %d\n", rgvswctl & 0x3f); | 
|---|
| 354 | drm_printf(p, f: "Current VID: %d\n", (rgvstat & MEMSTAT_VID_MASK) >> | 
|---|
| 355 | MEMSTAT_VID_SHIFT); | 
|---|
| 356 | drm_printf(p, f: "Current P-state: %d\n", | 
|---|
| 357 | REG_FIELD_GET(MEMSTAT_PSTATE_MASK, rgvstat)); | 
|---|
| 358 | } else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) { | 
|---|
| 359 | u32 rpmodectl, freq_sts; | 
|---|
| 360 |  | 
|---|
| 361 | rpmodectl = intel_uncore_read(uncore, GEN6_RP_CONTROL); | 
|---|
| 362 | drm_printf(p, f: "Video Turbo Mode: %s\n", | 
|---|
| 363 | str_yes_no(v: rpmodectl & GEN6_RP_MEDIA_TURBO)); | 
|---|
| 364 | drm_printf(p, f: "HW control enabled: %s\n", | 
|---|
| 365 | str_yes_no(v: rpmodectl & GEN6_RP_ENABLE)); | 
|---|
| 366 | drm_printf(p, f: "SW control enabled: %s\n", | 
|---|
| 367 | str_yes_no(v: (rpmodectl & GEN6_RP_MEDIA_MODE_MASK) == GEN6_RP_MEDIA_SW_MODE)); | 
|---|
| 368 |  | 
|---|
| 369 | vlv_iosf_sb_get(drm: &i915->drm, BIT(VLV_IOSF_SB_PUNIT)); | 
|---|
| 370 | freq_sts = vlv_iosf_sb_read(drm: &i915->drm, unit: VLV_IOSF_SB_PUNIT, PUNIT_REG_GPU_FREQ_STS); | 
|---|
| 371 | vlv_iosf_sb_put(drm: &i915->drm, BIT(VLV_IOSF_SB_PUNIT)); | 
|---|
| 372 |  | 
|---|
| 373 | drm_printf(p, f: "PUNIT_REG_GPU_FREQ_STS: 0x%08x\n", freq_sts); | 
|---|
| 374 |  | 
|---|
| 375 | drm_printf(p, f: "actual GPU freq: %d MHz\n", | 
|---|
| 376 | intel_gpu_freq(rps, val: (freq_sts >> 8) & 0xff)); | 
|---|
| 377 |  | 
|---|
| 378 | drm_printf(p, f: "current GPU freq: %d MHz\n", | 
|---|
| 379 | intel_gpu_freq(rps, val: rps->cur_freq)); | 
|---|
| 380 |  | 
|---|
| 381 | drm_printf(p, f: "max GPU freq: %d MHz\n", | 
|---|
| 382 | intel_gpu_freq(rps, val: rps->max_freq)); | 
|---|
| 383 |  | 
|---|
| 384 | drm_printf(p, f: "min GPU freq: %d MHz\n", | 
|---|
| 385 | intel_gpu_freq(rps, val: rps->min_freq)); | 
|---|
| 386 |  | 
|---|
| 387 | drm_printf(p, f: "idle GPU freq: %d MHz\n", | 
|---|
| 388 | intel_gpu_freq(rps, val: rps->idle_freq)); | 
|---|
| 389 |  | 
|---|
| 390 | drm_printf(p, f: "efficient (RPe) frequency: %d MHz\n", | 
|---|
| 391 | intel_gpu_freq(rps, val: rps->efficient_freq)); | 
|---|
| 392 | } else if (GRAPHICS_VER(i915) >= 6) { | 
|---|
| 393 | gen6_rps_frequency_dump(rps, p); | 
|---|
| 394 | } else { | 
|---|
| 395 | drm_puts(p, str: "no P-state info available\n"); | 
|---|
| 396 | } | 
|---|
| 397 |  | 
|---|
| 398 | intel_runtime_pm_put(rpm: uncore->rpm, wref: wakeref); | 
|---|
| 399 | } | 
|---|
| 400 |  | 
|---|
| 401 | static int frequency_show(struct seq_file *m, void *unused) | 
|---|
| 402 | { | 
|---|
| 403 | struct intel_gt *gt = m->private; | 
|---|
| 404 | struct drm_printer p = drm_seq_file_printer(f: m); | 
|---|
| 405 |  | 
|---|
| 406 | intel_gt_pm_frequency_dump(gt, p: &p); | 
|---|
| 407 |  | 
|---|
| 408 | return 0; | 
|---|
| 409 | } | 
|---|
| 410 | DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(frequency); | 
|---|
| 411 |  | 
|---|
| 412 | static int llc_show(struct seq_file *m, void *data) | 
|---|
| 413 | { | 
|---|
| 414 | struct intel_gt *gt = m->private; | 
|---|
| 415 | struct drm_i915_private *i915 = gt->i915; | 
|---|
| 416 | const bool edram = GRAPHICS_VER(i915) > 8; | 
|---|
| 417 | struct intel_rps *rps = >->rps; | 
|---|
| 418 | unsigned int max_gpu_freq, min_gpu_freq; | 
|---|
| 419 | intel_wakeref_t wakeref; | 
|---|
| 420 | int gpu_freq, ia_freq; | 
|---|
| 421 |  | 
|---|
| 422 | seq_printf(m, fmt: "LLC: %s\n", str_yes_no(HAS_LLC(i915))); | 
|---|
| 423 | seq_printf(m, fmt: "%s: %uMB\n", edram ? "eDRAM": "eLLC", | 
|---|
| 424 | i915->edram_size_mb); | 
|---|
| 425 |  | 
|---|
| 426 | min_gpu_freq = rps->min_freq; | 
|---|
| 427 | max_gpu_freq = rps->max_freq; | 
|---|
| 428 | if (IS_GEN9_BC(i915) || GRAPHICS_VER(i915) >= 11) { | 
|---|
| 429 | /* Convert GT frequency to 50 HZ units */ | 
|---|
| 430 | min_gpu_freq /= GEN9_FREQ_SCALER; | 
|---|
| 431 | max_gpu_freq /= GEN9_FREQ_SCALER; | 
|---|
| 432 | } | 
|---|
| 433 |  | 
|---|
| 434 | seq_puts(m, s: "GPU freq (MHz)\tEffective GPU freq (MHz)\tEffective Ring freq (MHz)\n"); | 
|---|
| 435 |  | 
|---|
| 436 | wakeref = intel_runtime_pm_get(rpm: gt->uncore->rpm); | 
|---|
| 437 | for (gpu_freq = min_gpu_freq; gpu_freq <= max_gpu_freq; gpu_freq++) { | 
|---|
| 438 | ia_freq = gpu_freq; | 
|---|
| 439 | snb_pcode_read(uncore: gt->uncore, GEN6_PCODE_READ_MIN_FREQ_TABLE, | 
|---|
| 440 | val: &ia_freq, NULL); | 
|---|
| 441 | seq_printf(m, fmt: "%d\t\t%d\t\t\t\t%d\n", | 
|---|
| 442 | intel_gpu_freq(rps, | 
|---|
| 443 | val: (gpu_freq * | 
|---|
| 444 | (IS_GEN9_BC(i915) || | 
|---|
| 445 | GRAPHICS_VER(i915) >= 11 ? | 
|---|
| 446 | GEN9_FREQ_SCALER : 1))), | 
|---|
| 447 | ((ia_freq >> 0) & 0xff) * 100, | 
|---|
| 448 | ((ia_freq >> 8) & 0xff) * 100); | 
|---|
| 449 | } | 
|---|
| 450 | intel_runtime_pm_put(rpm: gt->uncore->rpm, wref: wakeref); | 
|---|
| 451 |  | 
|---|
| 452 | return 0; | 
|---|
| 453 | } | 
|---|
| 454 |  | 
|---|
| 455 | static bool llc_eval(void *data) | 
|---|
| 456 | { | 
|---|
| 457 | struct intel_gt *gt = data; | 
|---|
| 458 |  | 
|---|
| 459 | return HAS_LLC(gt->i915); | 
|---|
| 460 | } | 
|---|
| 461 |  | 
|---|
| 462 | DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(llc); | 
|---|
| 463 |  | 
|---|
| 464 | static const char *rps_power_to_str(unsigned int power) | 
|---|
| 465 | { | 
|---|
| 466 | static const char * const strings[] = { | 
|---|
| 467 | [LOW_POWER] = "low power", | 
|---|
| 468 | [BETWEEN] = "mixed", | 
|---|
| 469 | [HIGH_POWER] = "high power", | 
|---|
| 470 | }; | 
|---|
| 471 |  | 
|---|
| 472 | if (power >= ARRAY_SIZE(strings) || !strings[power]) | 
|---|
| 473 | return "unknown"; | 
|---|
| 474 |  | 
|---|
| 475 | return strings[power]; | 
|---|
| 476 | } | 
|---|
| 477 |  | 
|---|
| 478 | static int rps_boost_show(struct seq_file *m, void *data) | 
|---|
| 479 | { | 
|---|
| 480 | struct intel_gt *gt = m->private; | 
|---|
| 481 | struct drm_i915_private *i915 = gt->i915; | 
|---|
| 482 | struct intel_rps *rps = >->rps; | 
|---|
| 483 |  | 
|---|
| 484 | seq_printf(m, fmt: "RPS enabled? %s\n", | 
|---|
| 485 | str_yes_no(v: intel_rps_is_enabled(rps))); | 
|---|
| 486 | seq_printf(m, fmt: "RPS active? %s\n", | 
|---|
| 487 | str_yes_no(v: intel_rps_is_active(rps))); | 
|---|
| 488 | seq_printf(m, fmt: "GPU busy? %s, %llums\n", | 
|---|
| 489 | str_yes_no(v: gt->awake), | 
|---|
| 490 | ktime_to_ms(kt: intel_gt_get_awake_time(gt))); | 
|---|
| 491 | seq_printf(m, fmt: "Boosts outstanding? %d\n", | 
|---|
| 492 | atomic_read(v: &rps->num_waiters)); | 
|---|
| 493 | seq_printf(m, fmt: "Interactive? %d\n", READ_ONCE(rps->power.interactive)); | 
|---|
| 494 | seq_printf(m, fmt: "Frequency requested %d, actual %d\n", | 
|---|
| 495 | intel_gpu_freq(rps, val: rps->cur_freq), | 
|---|
| 496 | intel_rps_read_actual_frequency(rps)); | 
|---|
| 497 | seq_printf(m, fmt: "  min hard:%d, soft:%d; max soft:%d, hard:%d\n", | 
|---|
| 498 | intel_gpu_freq(rps, val: rps->min_freq), | 
|---|
| 499 | intel_gpu_freq(rps, val: rps->min_freq_softlimit), | 
|---|
| 500 | intel_gpu_freq(rps, val: rps->max_freq_softlimit), | 
|---|
| 501 | intel_gpu_freq(rps, val: rps->max_freq)); | 
|---|
| 502 | seq_printf(m, fmt: "  idle:%d, efficient:%d, boost:%d\n", | 
|---|
| 503 | intel_gpu_freq(rps, val: rps->idle_freq), | 
|---|
| 504 | intel_gpu_freq(rps, val: rps->efficient_freq), | 
|---|
| 505 | intel_gpu_freq(rps, val: rps->boost_freq)); | 
|---|
| 506 |  | 
|---|
| 507 | seq_printf(m, fmt: "Wait boosts: %d\n", READ_ONCE(rps->boosts)); | 
|---|
| 508 |  | 
|---|
| 509 | if (GRAPHICS_VER(i915) >= 6 && intel_rps_is_active(rps)) { | 
|---|
| 510 | struct intel_uncore *uncore = gt->uncore; | 
|---|
| 511 | u32 rpup, rpupei; | 
|---|
| 512 | u32 rpdown, rpdownei; | 
|---|
| 513 |  | 
|---|
| 514 | intel_uncore_forcewake_get(uncore, domains: FORCEWAKE_ALL); | 
|---|
| 515 | rpup = intel_uncore_read_fw(uncore, GEN6_RP_CUR_UP) & GEN6_RP_EI_MASK; | 
|---|
| 516 | rpupei = intel_uncore_read_fw(uncore, GEN6_RP_CUR_UP_EI) & GEN6_RP_EI_MASK; | 
|---|
| 517 | rpdown = intel_uncore_read_fw(uncore, GEN6_RP_CUR_DOWN) & GEN6_RP_EI_MASK; | 
|---|
| 518 | rpdownei = intel_uncore_read_fw(uncore, GEN6_RP_CUR_DOWN_EI) & GEN6_RP_EI_MASK; | 
|---|
| 519 | intel_uncore_forcewake_put(uncore, domains: FORCEWAKE_ALL); | 
|---|
| 520 |  | 
|---|
| 521 | seq_printf(m, fmt: "\nRPS Autotuning (current \"%s\" window):\n", | 
|---|
| 522 | rps_power_to_str(power: rps->power.mode)); | 
|---|
| 523 | seq_printf(m, fmt: "  Avg. up: %d%% [above threshold? %d%%]\n", | 
|---|
| 524 | rpup && rpupei ? 100 * rpup / rpupei : 0, | 
|---|
| 525 | rps->power.up_threshold); | 
|---|
| 526 | seq_printf(m, fmt: "  Avg. down: %d%% [below threshold? %d%%]\n", | 
|---|
| 527 | rpdown && rpdownei ? 100 * rpdown / rpdownei : 0, | 
|---|
| 528 | rps->power.down_threshold); | 
|---|
| 529 | } else { | 
|---|
| 530 | seq_puts(m, s: "\nRPS Autotuning inactive\n"); | 
|---|
| 531 | } | 
|---|
| 532 |  | 
|---|
| 533 | return 0; | 
|---|
| 534 | } | 
|---|
| 535 |  | 
|---|
| 536 | static bool rps_eval(void *data) | 
|---|
| 537 | { | 
|---|
| 538 | struct intel_gt *gt = data; | 
|---|
| 539 |  | 
|---|
| 540 | if (intel_guc_slpc_is_used(guc: gt_to_guc(gt))) | 
|---|
| 541 | return false; | 
|---|
| 542 | else | 
|---|
| 543 | return HAS_RPS(gt->i915); | 
|---|
| 544 | } | 
|---|
| 545 |  | 
|---|
| 546 | DEFINE_INTEL_GT_DEBUGFS_ATTRIBUTE(rps_boost); | 
|---|
| 547 |  | 
|---|
| 548 | static int perf_limit_reasons_get(void *data, u64 *val) | 
|---|
| 549 | { | 
|---|
| 550 | struct intel_gt *gt = data; | 
|---|
| 551 | intel_wakeref_t wakeref; | 
|---|
| 552 |  | 
|---|
| 553 | with_intel_runtime_pm(gt->uncore->rpm, wakeref) | 
|---|
| 554 | *val = intel_uncore_read(uncore: gt->uncore, reg: intel_gt_perf_limit_reasons_reg(gt)); | 
|---|
| 555 |  | 
|---|
| 556 | return 0; | 
|---|
| 557 | } | 
|---|
| 558 |  | 
|---|
| 559 | static int perf_limit_reasons_clear(void *data, u64 val) | 
|---|
| 560 | { | 
|---|
| 561 | struct intel_gt *gt = data; | 
|---|
| 562 | intel_wakeref_t wakeref; | 
|---|
| 563 |  | 
|---|
| 564 | /* | 
|---|
| 565 | * Clear the upper 16 "log" bits, the lower 16 "status" bits are | 
|---|
| 566 | * read-only. The upper 16 "log" bits are identical to the lower 16 | 
|---|
| 567 | * "status" bits except that the "log" bits remain set until cleared. | 
|---|
| 568 | */ | 
|---|
| 569 | with_intel_runtime_pm(gt->uncore->rpm, wakeref) | 
|---|
| 570 | intel_uncore_rmw(uncore: gt->uncore, reg: intel_gt_perf_limit_reasons_reg(gt), | 
|---|
| 571 | GT0_PERF_LIMIT_REASONS_LOG_MASK, set: 0); | 
|---|
| 572 |  | 
|---|
| 573 | return 0; | 
|---|
| 574 | } | 
|---|
| 575 |  | 
|---|
| 576 | static bool perf_limit_reasons_eval(void *data) | 
|---|
| 577 | { | 
|---|
| 578 | struct intel_gt *gt = data; | 
|---|
| 579 |  | 
|---|
| 580 | return i915_mmio_reg_valid(intel_gt_perf_limit_reasons_reg(gt)); | 
|---|
| 581 | } | 
|---|
| 582 |  | 
|---|
| 583 | DEFINE_SIMPLE_ATTRIBUTE(perf_limit_reasons_fops, perf_limit_reasons_get, | 
|---|
| 584 | perf_limit_reasons_clear, "0x%llx\n"); | 
|---|
| 585 |  | 
|---|
| 586 | void intel_gt_pm_debugfs_register(struct intel_gt *gt, struct dentry *root) | 
|---|
| 587 | { | 
|---|
| 588 | static const struct intel_gt_debugfs_file files[] = { | 
|---|
| 589 | { "drpc", &drpc_fops, NULL }, | 
|---|
| 590 | { "frequency", &frequency_fops, NULL }, | 
|---|
| 591 | { "forcewake", &fw_domains_fops, NULL }, | 
|---|
| 592 | { "forcewake_user", &forcewake_user_fops, NULL}, | 
|---|
| 593 | { "llc", &llc_fops, llc_eval }, | 
|---|
| 594 | { "rps_boost", &rps_boost_fops, rps_eval }, | 
|---|
| 595 | { "perf_limit_reasons", &perf_limit_reasons_fops, perf_limit_reasons_eval }, | 
|---|
| 596 | }; | 
|---|
| 597 |  | 
|---|
| 598 | intel_gt_debugfs_register_files(root, files, ARRAY_SIZE(files), data: gt); | 
|---|
| 599 | } | 
|---|
| 600 |  | 
|---|