summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/common/linux/debug.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/common/linux/debug.c')
-rw-r--r--drivers/gpu/nvgpu/common/linux/debug.c376
1 files changed, 376 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/common/linux/debug.c b/drivers/gpu/nvgpu/common/linux/debug.c
new file mode 100644
index 00000000..2962a467
--- /dev/null
+++ b/drivers/gpu/nvgpu/common/linux/debug.c
@@ -0,0 +1,376 @@
1/*
2 * Copyright (C) 2017 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 "debug_cde.h"
16#include "debug_ce.h"
17#include "debug_fifo.h"
18#include "debug_gr.h"
19#include "debug_mm.h"
20#include "debug_allocator.h"
21#include "debug_kmem.h"
22#include "debug_pmu.h"
23#include "debug_sched.h"
24
25#include "gk20a/gk20a.h"
26#include "gk20a/platform_gk20a.h"
27
28#include <linux/debugfs.h>
29#include <linux/seq_file.h>
30
31#include <nvgpu/debug.h>
32
33unsigned int gk20a_debug_trace_cmdbuf;
34
35static inline void gk20a_debug_write_printk(void *ctx, const char *str,
36 size_t len)
37{
38 pr_info("%s", str);
39}
40
41static inline void gk20a_debug_write_to_seqfile(void *ctx, const char *str,
42 size_t len)
43{
44 seq_write((struct seq_file *)ctx, str, len);
45}
46
47void gk20a_debug_output(struct gk20a_debug_output *o,
48 const char *fmt, ...)
49{
50 va_list args;
51 int len;
52
53 va_start(args, fmt);
54 len = vsnprintf(o->buf, sizeof(o->buf), fmt, args);
55 va_end(args);
56 o->fn(o->ctx, o->buf, len);
57}
58
59static int gk20a_gr_dump_regs(struct gk20a *g,
60 struct gk20a_debug_output *o)
61{
62 if (g->ops.gr.dump_gr_regs)
63 gr_gk20a_elpg_protected_call(g, g->ops.gr.dump_gr_regs(g, o));
64
65 return 0;
66}
67
68int gk20a_gr_debug_dump(struct gk20a *g)
69{
70 struct gk20a_debug_output o = {
71 .fn = gk20a_debug_write_printk
72 };
73
74 gk20a_gr_dump_regs(g, &o);
75
76 return 0;
77}
78
79static int gk20a_gr_debug_show(struct seq_file *s, void *unused)
80{
81 struct device *dev = s->private;
82 struct gk20a *g = gk20a_get_platform(dev)->g;
83 struct gk20a_debug_output o = {
84 .fn = gk20a_debug_write_to_seqfile,
85 .ctx = s,
86 };
87 int err;
88
89 err = gk20a_busy(g);
90 if (err) {
91 nvgpu_err(g, "failed to power on gpu: %d", err);
92 return -EINVAL;
93 }
94
95 gk20a_gr_dump_regs(g, &o);
96
97 gk20a_idle(g);
98
99 return 0;
100}
101
102void gk20a_debug_dump(struct gk20a *g)
103{
104 struct gk20a_platform *platform = gk20a_get_platform(g->dev);
105 struct gk20a_debug_output o = {
106 .fn = gk20a_debug_write_printk
107 };
108
109 if (platform->dump_platform_dependencies)
110 platform->dump_platform_dependencies(g->dev);
111
112 /* HAL only initialized after 1st power-on */
113 if (g->ops.debug.show_dump)
114 g->ops.debug.show_dump(g, &o);
115}
116
117static int gk20a_debug_show(struct seq_file *s, void *unused)
118{
119 struct device *dev = s->private;
120 struct gk20a_debug_output o = {
121 .fn = gk20a_debug_write_to_seqfile,
122 .ctx = s,
123 };
124 struct gk20a *g;
125 int err;
126
127 g = gk20a_get_platform(dev)->g;
128
129 err = gk20a_busy(g);
130 if (err) {
131 nvgpu_err(g, "failed to power on gpu: %d", err);
132 return -EFAULT;
133 }
134
135 /* HAL only initialized after 1st power-on */
136 if (g->ops.debug.show_dump)
137 g->ops.debug.show_dump(g, &o);
138
139 gk20a_idle(g);
140 return 0;
141}
142
143static int gk20a_gr_debug_open(struct inode *inode, struct file *file)
144{
145 return single_open(file, gk20a_gr_debug_show, inode->i_private);
146}
147
148static int gk20a_debug_open(struct inode *inode, struct file *file)
149{
150 return single_open(file, gk20a_debug_show, inode->i_private);
151}
152
153static const struct file_operations gk20a_gr_debug_fops = {
154 .open = gk20a_gr_debug_open,
155 .read = seq_read,
156 .llseek = seq_lseek,
157 .release = single_release,
158};
159
160static const struct file_operations gk20a_debug_fops = {
161 .open = gk20a_debug_open,
162 .read = seq_read,
163 .llseek = seq_lseek,
164 .release = single_release,
165};
166
167void gk20a_debug_show_dump(struct gk20a *g, struct gk20a_debug_output *o)
168{
169 g->ops.fifo.dump_pbdma_status(g, o);
170 g->ops.fifo.dump_eng_status(g, o);
171
172 gk20a_debug_dump_all_channel_status_ramfc(g, o);
173}
174
175void gk20a_init_debug_ops(struct gpu_ops *gops)
176{
177 gops->debug.show_dump = gk20a_debug_show_dump;
178}
179
180static int railgate_residency_show(struct seq_file *s, void *data)
181{
182 struct gk20a *g = s->private;
183 struct gk20a_platform *platform = dev_get_drvdata(g->dev);
184 unsigned long time_since_last_state_transition_ms;
185 unsigned long total_rail_gate_time_ms;
186 unsigned long total_rail_ungate_time_ms;
187
188 if (platform->is_railgated(g->dev)) {
189 time_since_last_state_transition_ms =
190 jiffies_to_msecs(jiffies -
191 g->pstats.last_rail_gate_complete);
192 total_rail_ungate_time_ms = g->pstats.total_rail_ungate_time_ms;
193 total_rail_gate_time_ms =
194 g->pstats.total_rail_gate_time_ms +
195 time_since_last_state_transition_ms;
196 } else {
197 time_since_last_state_transition_ms =
198 jiffies_to_msecs(jiffies -
199 g->pstats.last_rail_ungate_complete);
200 total_rail_gate_time_ms = g->pstats.total_rail_gate_time_ms;
201 total_rail_ungate_time_ms =
202 g->pstats.total_rail_ungate_time_ms +
203 time_since_last_state_transition_ms;
204 }
205
206 seq_printf(s, "Time with Rails Gated: %lu ms\n"
207 "Time with Rails UnGated: %lu ms\n"
208 "Total railgating cycles: %lu\n",
209 total_rail_gate_time_ms,
210 total_rail_ungate_time_ms,
211 g->pstats.railgating_cycle_count - 1);
212 return 0;
213
214}
215
216static int railgate_residency_open(struct inode *inode, struct file *file)
217{
218 return single_open(file, railgate_residency_show, inode->i_private);
219}
220
221static const struct file_operations railgate_residency_fops = {
222 .open = railgate_residency_open,
223 .read = seq_read,
224 .llseek = seq_lseek,
225 .release = single_release,
226};
227
228static int gk20a_railgating_debugfs_init(struct gk20a *g)
229{
230 struct gk20a_platform *platform = dev_get_drvdata(g->dev);
231 struct dentry *d;
232
233 if (!g->can_railgate)
234 return 0;
235
236 d = debugfs_create_file(
237 "railgate_residency", S_IRUGO|S_IWUSR, platform->debugfs, g,
238 &railgate_residency_fops);
239 if (!d)
240 return -ENOMEM;
241
242 return 0;
243}
244
245void gk20a_debug_init(struct gk20a *g, const char *debugfs_symlink)
246{
247 struct device *dev = g->dev;
248 struct gk20a_platform *platform = dev_get_drvdata(dev);
249
250 platform->debugfs = debugfs_create_dir(dev_name(dev), NULL);
251 if (!platform->debugfs)
252 return;
253
254 if (debugfs_symlink)
255 platform->debugfs_alias =
256 debugfs_create_symlink(debugfs_symlink,
257 NULL, dev_name(dev));
258
259 debugfs_create_file("status", S_IRUGO, platform->debugfs,
260 dev, &gk20a_debug_fops);
261 debugfs_create_file("gr_status", S_IRUGO, platform->debugfs,
262 dev, &gk20a_gr_debug_fops);
263 debugfs_create_u32("trace_cmdbuf", S_IRUGO|S_IWUSR,
264 platform->debugfs, &gk20a_debug_trace_cmdbuf);
265
266 debugfs_create_u32("ch_wdt_timeout_ms", S_IRUGO|S_IWUSR,
267 platform->debugfs, &g->ch_wdt_timeout_ms);
268
269 debugfs_create_u32("disable_syncpoints", S_IRUGO|S_IWUSR,
270 platform->debugfs, &g->disable_syncpoints);
271
272 /* Legacy debugging API. */
273 debugfs_create_u32("dbg_mask", S_IRUGO|S_IWUSR,
274 platform->debugfs, &nvgpu_dbg_mask);
275
276 /* New debug logging API. */
277 debugfs_create_u32("log_mask", S_IRUGO|S_IWUSR,
278 platform->debugfs, &g->log_mask);
279 debugfs_create_u32("log_trace", S_IRUGO|S_IWUSR,
280 platform->debugfs, &g->log_trace);
281
282 nvgpu_spinlock_init(&g->debugfs_lock);
283
284 g->mm.ltc_enabled = true;
285 g->mm.ltc_enabled_debug = true;
286
287 g->debugfs_ltc_enabled =
288 debugfs_create_bool("ltc_enabled", S_IRUGO|S_IWUSR,
289 platform->debugfs,
290 &g->mm.ltc_enabled_debug);
291
292 g->debugfs_gr_idle_timeout_default =
293 debugfs_create_u32("gr_idle_timeout_default_us",
294 S_IRUGO|S_IWUSR, platform->debugfs,
295 &g->gr_idle_timeout_default);
296 g->debugfs_timeouts_enabled =
297 debugfs_create_bool("timeouts_enabled",
298 S_IRUGO|S_IWUSR,
299 platform->debugfs,
300 &g->timeouts_enabled);
301
302 g->debugfs_bypass_smmu =
303 debugfs_create_bool("bypass_smmu",
304 S_IRUGO|S_IWUSR,
305 platform->debugfs,
306 &g->mm.bypass_smmu);
307 g->debugfs_disable_bigpage =
308 debugfs_create_bool("disable_bigpage",
309 S_IRUGO|S_IWUSR,
310 platform->debugfs,
311 &g->mm.disable_bigpage);
312
313 g->debugfs_timeslice_low_priority_us =
314 debugfs_create_u32("timeslice_low_priority_us",
315 S_IRUGO|S_IWUSR,
316 platform->debugfs,
317 &g->timeslice_low_priority_us);
318 g->debugfs_timeslice_medium_priority_us =
319 debugfs_create_u32("timeslice_medium_priority_us",
320 S_IRUGO|S_IWUSR,
321 platform->debugfs,
322 &g->timeslice_medium_priority_us);
323 g->debugfs_timeslice_high_priority_us =
324 debugfs_create_u32("timeslice_high_priority_us",
325 S_IRUGO|S_IWUSR,
326 platform->debugfs,
327 &g->timeslice_high_priority_us);
328 g->debugfs_runlist_interleave =
329 debugfs_create_bool("runlist_interleave",
330 S_IRUGO|S_IWUSR,
331 platform->debugfs,
332 &g->runlist_interleave);
333#ifdef CONFIG_ARCH_TEGRA_18x_SOC
334 g->gr.t18x.ctx_vars.debugfs_force_preemption_gfxp =
335 debugfs_create_bool("force_preemption_gfxp", S_IRUGO|S_IWUSR,
336 platform->debugfs,
337 &g->gr.t18x.ctx_vars.force_preemption_gfxp);
338
339 g->gr.t18x.ctx_vars.debugfs_force_preemption_cilp =
340 debugfs_create_bool("force_preemption_cilp", S_IRUGO|S_IWUSR,
341 platform->debugfs,
342 &g->gr.t18x.ctx_vars.force_preemption_cilp);
343
344 g->gr.t18x.ctx_vars.debugfs_dump_ctxsw_stats =
345 debugfs_create_bool("dump_ctxsw_stats_on_channel_close",
346 S_IRUGO|S_IWUSR, platform->debugfs,
347 &g->gr.t18x.
348 ctx_vars.dump_ctxsw_stats_on_channel_close);
349#endif
350
351 gr_gk20a_debugfs_init(g);
352 gk20a_pmu_debugfs_init(g);
353 gk20a_railgating_debugfs_init(g);
354 gk20a_cde_debugfs_init(g);
355 gk20a_ce_debugfs_init(g);
356 nvgpu_alloc_debugfs_init(g);
357 gk20a_mm_debugfs_init(g);
358 gk20a_fifo_debugfs_init(g);
359 gk20a_sched_debugfs_init(g);
360#ifdef CONFIG_NVGPU_TRACK_MEM_USAGE
361 nvgpu_kmem_debugfs_init(g);
362#endif
363}
364
365void gk20a_debug_deinit(struct gk20a *g)
366{
367 struct gk20a_platform *platform = dev_get_drvdata(g->dev);
368
369 if (!platform->debugfs)
370 return;
371
372 gk20a_fifo_debugfs_deinit(g);
373
374 debugfs_remove_recursive(platform->debugfs);
375 debugfs_remove_recursive(platform->debugfs_alias);
376}