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