diff options
author | Joshua Bakita <bakitajoshua@gmail.com> | 2024-09-25 16:09:09 -0400 |
---|---|---|
committer | Joshua Bakita <bakitajoshua@gmail.com> | 2024-09-25 16:09:09 -0400 |
commit | f347fde22f1297e4f022600d201780d5ead78114 (patch) | |
tree | 76be305d6187003a1e0486ff6e91efb1062ae118 /include/os/linux/debug_pmu.c | |
parent | 8340d234d78a7d0f46c11a584de538148b78b7cb (diff) |
Delete no-longer-needed nvgpu headersHEADmasterjbakita-wip
The dependency on these was removed in commit 8340d234.
Diffstat (limited to 'include/os/linux/debug_pmu.c')
-rw-r--r-- | include/os/linux/debug_pmu.c | 484 |
1 files changed, 0 insertions, 484 deletions
diff --git a/include/os/linux/debug_pmu.c b/include/os/linux/debug_pmu.c deleted file mode 100644 index f3e36d0..0000000 --- a/include/os/linux/debug_pmu.c +++ /dev/null | |||
@@ -1,484 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017-2019 NVIDIA Corporation. All rights reserved. | ||
3 | * | ||
4 | * This software is licensed under the terms of the GNU General Public | ||
5 | * License version 2, as published by the Free Software Foundation, and | ||
6 | * may be copied, distributed, and modified under those terms. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <nvgpu/enabled.h> | ||
16 | #include "debug_pmu.h" | ||
17 | #include "os_linux.h" | ||
18 | |||
19 | #include <linux/debugfs.h> | ||
20 | #include <linux/seq_file.h> | ||
21 | #include <linux/uaccess.h> | ||
22 | |||
23 | static int lpwr_debug_show(struct seq_file *s, void *data) | ||
24 | { | ||
25 | struct gk20a *g = s->private; | ||
26 | |||
27 | if (g->ops.pmu.pmu_pg_engines_feature_list && | ||
28 | g->ops.pmu.pmu_pg_engines_feature_list(g, | ||
29 | PMU_PG_ELPG_ENGINE_ID_GRAPHICS) != | ||
30 | NVGPU_PMU_GR_FEATURE_MASK_POWER_GATING) { | ||
31 | seq_printf(s, "PSTATE: %u\n" | ||
32 | "RPPG Enabled: %u\n" | ||
33 | "RPPG ref count: %u\n" | ||
34 | "RPPG state: %u\n" | ||
35 | "MSCG Enabled: %u\n" | ||
36 | "MSCG pstate state: %u\n" | ||
37 | "MSCG transition state: %u\n", | ||
38 | g->ops.clk_arb.get_current_pstate(g), | ||
39 | g->elpg_enabled, g->pmu.elpg_refcnt, | ||
40 | g->pmu.elpg_stat, g->mscg_enabled, | ||
41 | g->pmu.mscg_stat, g->pmu.mscg_transition_state); | ||
42 | |||
43 | } else | ||
44 | seq_printf(s, "ELPG Enabled: %u\n" | ||
45 | "ELPG ref count: %u\n" | ||
46 | "ELPG state: %u\n", | ||
47 | g->elpg_enabled, g->pmu.elpg_refcnt, | ||
48 | g->pmu.elpg_stat); | ||
49 | |||
50 | return 0; | ||
51 | |||
52 | } | ||
53 | |||
54 | static int lpwr_debug_open(struct inode *inode, struct file *file) | ||
55 | { | ||
56 | return single_open(file, lpwr_debug_show, inode->i_private); | ||
57 | } | ||
58 | |||
59 | static const struct file_operations lpwr_debug_fops = { | ||
60 | .open = lpwr_debug_open, | ||
61 | .read = seq_read, | ||
62 | .llseek = seq_lseek, | ||
63 | .release = single_release, | ||
64 | }; | ||
65 | |||
66 | static int mscg_stat_show(struct seq_file *s, void *data) | ||
67 | { | ||
68 | struct gk20a *g = s->private; | ||
69 | u64 total_ingating, total_ungating, residency, divisor, dividend; | ||
70 | struct pmu_pg_stats_data pg_stat_data = { 0 }; | ||
71 | int err; | ||
72 | |||
73 | /* Don't unnecessarily power on the device */ | ||
74 | if (g->power_on) { | ||
75 | err = gk20a_busy(g); | ||
76 | if (err) | ||
77 | return err; | ||
78 | |||
79 | nvgpu_pmu_get_pg_stats(g, | ||
80 | PMU_PG_ELPG_ENGINE_ID_MS, &pg_stat_data); | ||
81 | gk20a_idle(g); | ||
82 | } | ||
83 | total_ingating = g->pg_ingating_time_us + | ||
84 | (u64)pg_stat_data.ingating_time; | ||
85 | total_ungating = g->pg_ungating_time_us + | ||
86 | (u64)pg_stat_data.ungating_time; | ||
87 | |||
88 | divisor = total_ingating + total_ungating; | ||
89 | |||
90 | /* We compute the residency on a scale of 1000 */ | ||
91 | dividend = total_ingating * 1000; | ||
92 | |||
93 | if (divisor) | ||
94 | residency = div64_u64(dividend, divisor); | ||
95 | else | ||
96 | residency = 0; | ||
97 | |||
98 | seq_printf(s, | ||
99 | "Time in MSCG: %llu us\n" | ||
100 | "Time out of MSCG: %llu us\n" | ||
101 | "MSCG residency ratio: %llu\n" | ||
102 | "MSCG Entry Count: %u\n" | ||
103 | "MSCG Avg Entry latency %u\n" | ||
104 | "MSCG Avg Exit latency %u\n", | ||
105 | total_ingating, total_ungating, | ||
106 | residency, pg_stat_data.gating_cnt, | ||
107 | pg_stat_data.avg_entry_latency_us, | ||
108 | pg_stat_data.avg_exit_latency_us); | ||
109 | return 0; | ||
110 | |||
111 | } | ||
112 | |||
113 | static int mscg_stat_open(struct inode *inode, struct file *file) | ||
114 | { | ||
115 | return single_open(file, mscg_stat_show, inode->i_private); | ||
116 | } | ||
117 | |||
118 | static const struct file_operations mscg_stat_fops = { | ||
119 | .open = mscg_stat_open, | ||
120 | .read = seq_read, | ||
121 | .llseek = seq_lseek, | ||
122 | .release = single_release, | ||
123 | }; | ||
124 | |||
125 | static int mscg_transitions_show(struct seq_file *s, void *data) | ||
126 | { | ||
127 | struct gk20a *g = s->private; | ||
128 | struct pmu_pg_stats_data pg_stat_data = { 0 }; | ||
129 | u32 total_gating_cnt; | ||
130 | int err; | ||
131 | |||
132 | if (g->power_on) { | ||
133 | err = gk20a_busy(g); | ||
134 | if (err) | ||
135 | return err; | ||
136 | |||
137 | nvgpu_pmu_get_pg_stats(g, | ||
138 | PMU_PG_ELPG_ENGINE_ID_MS, &pg_stat_data); | ||
139 | gk20a_idle(g); | ||
140 | } | ||
141 | total_gating_cnt = g->pg_gating_cnt + pg_stat_data.gating_cnt; | ||
142 | |||
143 | seq_printf(s, "%u\n", total_gating_cnt); | ||
144 | return 0; | ||
145 | |||
146 | } | ||
147 | |||
148 | static int mscg_transitions_open(struct inode *inode, struct file *file) | ||
149 | { | ||
150 | return single_open(file, mscg_transitions_show, inode->i_private); | ||
151 | } | ||
152 | |||
153 | static const struct file_operations mscg_transitions_fops = { | ||
154 | .open = mscg_transitions_open, | ||
155 | .read = seq_read, | ||
156 | .llseek = seq_lseek, | ||
157 | .release = single_release, | ||
158 | }; | ||
159 | |||
160 | static int elpg_stat_show(struct seq_file *s, void *data) | ||
161 | { | ||
162 | struct gk20a *g = s->private; | ||
163 | struct pmu_pg_stats_data pg_stat_data = { 0 }; | ||
164 | u64 total_ingating, total_ungating, residency, divisor, dividend; | ||
165 | int err; | ||
166 | |||
167 | /* Don't unnecessarily power on the device */ | ||
168 | if (g->power_on) { | ||
169 | err = gk20a_busy(g); | ||
170 | if (err) | ||
171 | return err; | ||
172 | |||
173 | nvgpu_pmu_get_pg_stats(g, | ||
174 | PMU_PG_ELPG_ENGINE_ID_GRAPHICS, &pg_stat_data); | ||
175 | gk20a_idle(g); | ||
176 | } | ||
177 | total_ingating = g->pg_ingating_time_us + | ||
178 | (u64)pg_stat_data.ingating_time; | ||
179 | total_ungating = g->pg_ungating_time_us + | ||
180 | (u64)pg_stat_data.ungating_time; | ||
181 | divisor = total_ingating + total_ungating; | ||
182 | |||
183 | /* We compute the residency on a scale of 1000 */ | ||
184 | dividend = total_ingating * 1000; | ||
185 | |||
186 | if (divisor) | ||
187 | residency = div64_u64(dividend, divisor); | ||
188 | else | ||
189 | residency = 0; | ||
190 | |||
191 | seq_printf(s, | ||
192 | "Time in ELPG: %llu us\n" | ||
193 | "Time out of ELPG: %llu us\n" | ||
194 | "ELPG residency ratio: %llu\n" | ||
195 | "ELPG Entry Count: %u\n" | ||
196 | "ELPG Avg Entry latency %u us\n" | ||
197 | "ELPG Avg Exit latency %u us\n", | ||
198 | total_ingating, total_ungating, | ||
199 | residency, pg_stat_data.gating_cnt, | ||
200 | pg_stat_data.avg_entry_latency_us, | ||
201 | pg_stat_data.avg_exit_latency_us); | ||
202 | return 0; | ||
203 | |||
204 | } | ||
205 | |||
206 | static int elpg_stat_open(struct inode *inode, struct file *file) | ||
207 | { | ||
208 | return single_open(file, elpg_stat_show, inode->i_private); | ||
209 | } | ||
210 | |||
211 | static const struct file_operations elpg_stat_fops = { | ||
212 | .open = elpg_stat_open, | ||
213 | .read = seq_read, | ||
214 | .llseek = seq_lseek, | ||
215 | .release = single_release, | ||
216 | }; | ||
217 | |||
218 | static int elpg_transitions_show(struct seq_file *s, void *data) | ||
219 | { | ||
220 | struct gk20a *g = s->private; | ||
221 | struct pmu_pg_stats_data pg_stat_data = { 0 }; | ||
222 | u32 total_gating_cnt; | ||
223 | int err; | ||
224 | |||
225 | if (g->power_on) { | ||
226 | err = gk20a_busy(g); | ||
227 | if (err) | ||
228 | return err; | ||
229 | |||
230 | nvgpu_pmu_get_pg_stats(g, | ||
231 | PMU_PG_ELPG_ENGINE_ID_GRAPHICS, &pg_stat_data); | ||
232 | gk20a_idle(g); | ||
233 | } | ||
234 | total_gating_cnt = g->pg_gating_cnt + pg_stat_data.gating_cnt; | ||
235 | |||
236 | seq_printf(s, "%u\n", total_gating_cnt); | ||
237 | return 0; | ||
238 | |||
239 | } | ||
240 | |||
241 | static int elpg_transitions_open(struct inode *inode, struct file *file) | ||
242 | { | ||
243 | return single_open(file, elpg_transitions_show, inode->i_private); | ||
244 | } | ||
245 | |||
246 | static const struct file_operations elpg_transitions_fops = { | ||
247 | .open = elpg_transitions_open, | ||
248 | .read = seq_read, | ||
249 | .llseek = seq_lseek, | ||
250 | .release = single_release, | ||
251 | }; | ||
252 | |||
253 | static int falc_trace_show(struct seq_file *s, void *data) | ||
254 | { | ||
255 | struct gk20a *g = s->private; | ||
256 | struct nvgpu_pmu *pmu = &g->pmu; | ||
257 | u32 i = 0, j = 0, k, l, m; | ||
258 | char part_str[40]; | ||
259 | void *tracebuffer; | ||
260 | char *trace; | ||
261 | u32 *trace1; | ||
262 | |||
263 | /* allocate system memory to copy pmu trace buffer */ | ||
264 | tracebuffer = nvgpu_kzalloc(g, GK20A_PMU_TRACE_BUFSIZE); | ||
265 | if (tracebuffer == NULL) | ||
266 | return -ENOMEM; | ||
267 | |||
268 | /* read pmu traces into system memory buffer */ | ||
269 | nvgpu_mem_rd_n(g, &pmu->trace_buf, | ||
270 | 0, tracebuffer, GK20A_PMU_TRACE_BUFSIZE); | ||
271 | |||
272 | trace = (char *)tracebuffer; | ||
273 | trace1 = (u32 *)tracebuffer; | ||
274 | |||
275 | for (i = 0; i < GK20A_PMU_TRACE_BUFSIZE; i += 0x40) { | ||
276 | for (j = 0; j < 0x40; j++) | ||
277 | if (trace1[(i / 4) + j]) | ||
278 | break; | ||
279 | if (j == 0x40) | ||
280 | break; | ||
281 | seq_printf(s, "Index %x: ", trace1[(i / 4)]); | ||
282 | l = 0; | ||
283 | m = 0; | ||
284 | while (nvgpu_find_hex_in_string((trace+i+20+m), g, &k)) { | ||
285 | if (k >= 40) | ||
286 | break; | ||
287 | strncpy(part_str, (trace+i+20+m), k); | ||
288 | part_str[k] = 0; | ||
289 | seq_printf(s, "%s0x%x", part_str, | ||
290 | trace1[(i / 4) + 1 + l]); | ||
291 | l++; | ||
292 | m += k + 2; | ||
293 | } | ||
294 | seq_printf(s, "%s", (trace+i+20+m)); | ||
295 | } | ||
296 | |||
297 | nvgpu_kfree(g, tracebuffer); | ||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | static int falc_trace_open(struct inode *inode, struct file *file) | ||
302 | { | ||
303 | return single_open(file, falc_trace_show, inode->i_private); | ||
304 | } | ||
305 | |||
306 | static const struct file_operations falc_trace_fops = { | ||
307 | .open = falc_trace_open, | ||
308 | .read = seq_read, | ||
309 | .llseek = seq_lseek, | ||
310 | .release = single_release, | ||
311 | }; | ||
312 | |||
313 | static int perfmon_events_enable_show(struct seq_file *s, void *data) | ||
314 | { | ||
315 | struct gk20a *g = s->private; | ||
316 | |||
317 | seq_printf(s, "%u\n", g->pmu.perfmon_sampling_enabled ? 1 : 0); | ||
318 | return 0; | ||
319 | |||
320 | } | ||
321 | |||
322 | static int perfmon_events_enable_open(struct inode *inode, struct file *file) | ||
323 | { | ||
324 | return single_open(file, perfmon_events_enable_show, inode->i_private); | ||
325 | } | ||
326 | |||
327 | static ssize_t perfmon_events_enable_write(struct file *file, | ||
328 | const char __user *userbuf, size_t count, loff_t *ppos) | ||
329 | { | ||
330 | struct seq_file *s = file->private_data; | ||
331 | struct gk20a *g = s->private; | ||
332 | unsigned long val = 0; | ||
333 | char buf[40]; | ||
334 | int buf_size; | ||
335 | int err; | ||
336 | |||
337 | memset(buf, 0, sizeof(buf)); | ||
338 | buf_size = min(count, (sizeof(buf)-1)); | ||
339 | |||
340 | if (copy_from_user(buf, userbuf, buf_size)) | ||
341 | return -EFAULT; | ||
342 | |||
343 | if (kstrtoul(buf, 10, &val) < 0) | ||
344 | return -EINVAL; | ||
345 | |||
346 | /* Don't turn on gk20a unnecessarily */ | ||
347 | if (g->power_on) { | ||
348 | err = gk20a_busy(g); | ||
349 | if (err) | ||
350 | return err; | ||
351 | |||
352 | if (val && !g->pmu.perfmon_sampling_enabled && | ||
353 | nvgpu_is_enabled(g, NVGPU_PMU_PERFMON)) { | ||
354 | g->pmu.perfmon_sampling_enabled = true; | ||
355 | g->ops.pmu.pmu_perfmon_start_sampling(&(g->pmu)); | ||
356 | } else if (!val && g->pmu.perfmon_sampling_enabled && | ||
357 | nvgpu_is_enabled(g, NVGPU_PMU_PERFMON)) { | ||
358 | g->pmu.perfmon_sampling_enabled = false; | ||
359 | g->ops.pmu.pmu_perfmon_stop_sampling(&(g->pmu)); | ||
360 | } | ||
361 | gk20a_idle(g); | ||
362 | } else { | ||
363 | g->pmu.perfmon_sampling_enabled = val ? true : false; | ||
364 | } | ||
365 | |||
366 | return count; | ||
367 | } | ||
368 | |||
369 | static const struct file_operations perfmon_events_enable_fops = { | ||
370 | .open = perfmon_events_enable_open, | ||
371 | .read = seq_read, | ||
372 | .write = perfmon_events_enable_write, | ||
373 | .llseek = seq_lseek, | ||
374 | .release = single_release, | ||
375 | }; | ||
376 | |||
377 | static int perfmon_events_count_show(struct seq_file *s, void *data) | ||
378 | { | ||
379 | struct gk20a *g = s->private; | ||
380 | |||
381 | seq_printf(s, "%lu\n", g->pmu.perfmon_events_cnt); | ||
382 | return 0; | ||
383 | |||
384 | } | ||
385 | |||
386 | static int perfmon_events_count_open(struct inode *inode, struct file *file) | ||
387 | { | ||
388 | return single_open(file, perfmon_events_count_show, inode->i_private); | ||
389 | } | ||
390 | |||
391 | static const struct file_operations perfmon_events_count_fops = { | ||
392 | .open = perfmon_events_count_open, | ||
393 | .read = seq_read, | ||
394 | .llseek = seq_lseek, | ||
395 | .release = single_release, | ||
396 | }; | ||
397 | |||
398 | static int security_show(struct seq_file *s, void *data) | ||
399 | { | ||
400 | struct gk20a *g = s->private; | ||
401 | |||
402 | seq_printf(s, "%d\n", g->pmu.pmu_mode); | ||
403 | return 0; | ||
404 | |||
405 | } | ||
406 | |||
407 | static int security_open(struct inode *inode, struct file *file) | ||
408 | { | ||
409 | return single_open(file, security_show, inode->i_private); | ||
410 | } | ||
411 | |||
412 | static const struct file_operations security_fops = { | ||
413 | .open = security_open, | ||
414 | .read = seq_read, | ||
415 | .llseek = seq_lseek, | ||
416 | .release = single_release, | ||
417 | }; | ||
418 | |||
419 | int gk20a_pmu_debugfs_init(struct gk20a *g) | ||
420 | { | ||
421 | struct dentry *d; | ||
422 | struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); | ||
423 | |||
424 | d = debugfs_create_file( | ||
425 | "lpwr_debug", S_IRUGO|S_IWUSR, l->debugfs, g, | ||
426 | &lpwr_debug_fops); | ||
427 | if (!d) | ||
428 | goto err_out; | ||
429 | |||
430 | d = debugfs_create_file( | ||
431 | "mscg_residency", S_IRUGO|S_IWUSR, l->debugfs, g, | ||
432 | &mscg_stat_fops); | ||
433 | if (!d) | ||
434 | goto err_out; | ||
435 | |||
436 | d = debugfs_create_file( | ||
437 | "mscg_transitions", S_IRUGO, l->debugfs, g, | ||
438 | &mscg_transitions_fops); | ||
439 | if (!d) | ||
440 | goto err_out; | ||
441 | |||
442 | d = debugfs_create_file( | ||
443 | "elpg_residency", S_IRUGO|S_IWUSR, l->debugfs, g, | ||
444 | &elpg_stat_fops); | ||
445 | if (!d) | ||
446 | goto err_out; | ||
447 | |||
448 | d = debugfs_create_file( | ||
449 | "elpg_transitions", S_IRUGO, l->debugfs, g, | ||
450 | &elpg_transitions_fops); | ||
451 | if (!d) | ||
452 | goto err_out; | ||
453 | |||
454 | d = debugfs_create_file( | ||
455 | "pmu_security", S_IRUGO, l->debugfs, g, | ||
456 | &security_fops); | ||
457 | if (!d) | ||
458 | goto err_out; | ||
459 | |||
460 | /* No access to PMU if virtual */ | ||
461 | if (!g->is_virtual) { | ||
462 | d = debugfs_create_file( | ||
463 | "falc_trace", S_IRUGO, l->debugfs, g, | ||
464 | &falc_trace_fops); | ||
465 | if (!d) | ||
466 | goto err_out; | ||
467 | |||
468 | d = debugfs_create_file( | ||
469 | "perfmon_events_enable", S_IRUGO, l->debugfs, g, | ||
470 | &perfmon_events_enable_fops); | ||
471 | if (!d) | ||
472 | goto err_out; | ||
473 | |||
474 | d = debugfs_create_file( | ||
475 | "perfmon_events_count", S_IRUGO, l->debugfs, g, | ||
476 | &perfmon_events_count_fops); | ||
477 | if (!d) | ||
478 | goto err_out; | ||
479 | } | ||
480 | return 0; | ||
481 | err_out: | ||
482 | pr_err("%s: Failed to make debugfs node\n", __func__); | ||
483 | return -ENOMEM; | ||
484 | } | ||