]>
Commit | Line | Data |
---|---|---|
9c92ab61 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
6236451d TB |
2 | /* |
3 | * Copyright (C) 2010 Google, Inc. | |
4 | * Author: Erik Gilling <konkers@android.com> | |
5 | * | |
6 | * Copyright (C) 2011-2013 NVIDIA Corporation | |
6236451d TB |
7 | */ |
8 | ||
9 | #include <linux/debugfs.h> | |
10 | #include <linux/seq_file.h> | |
11 | #include <linux/uaccess.h> | |
12 | ||
13 | #include <linux/io.h> | |
14 | ||
15 | #include "dev.h" | |
16 | #include "debug.h" | |
17 | #include "channel.h" | |
18 | ||
19 | unsigned int host1x_debug_trace_cmdbuf; | |
20 | ||
21 | static pid_t host1x_debug_force_timeout_pid; | |
22 | static u32 host1x_debug_force_timeout_val; | |
23 | static u32 host1x_debug_force_timeout_channel; | |
24 | ||
25 | void host1x_debug_output(struct output *o, const char *fmt, ...) | |
26 | { | |
27 | va_list args; | |
28 | int len; | |
29 | ||
30 | va_start(args, fmt); | |
31 | len = vsnprintf(o->buf, sizeof(o->buf), fmt, args); | |
32 | va_end(args); | |
0b8070d1 | 33 | |
eb2ee1a2 MP |
34 | o->fn(o->ctx, o->buf, len, false); |
35 | } | |
36 | ||
37 | void host1x_debug_cont(struct output *o, const char *fmt, ...) | |
38 | { | |
39 | va_list args; | |
40 | int len; | |
41 | ||
42 | va_start(args, fmt); | |
43 | len = vsnprintf(o->buf, sizeof(o->buf), fmt, args); | |
44 | va_end(args); | |
45 | ||
46 | o->fn(o->ctx, o->buf, len, true); | |
6236451d TB |
47 | } |
48 | ||
8474b025 | 49 | static int show_channel(struct host1x_channel *ch, void *data, bool show_fifo) |
6236451d TB |
50 | { |
51 | struct host1x *m = dev_get_drvdata(ch->dev->parent); | |
52 | struct output *o = data; | |
53 | ||
8474b025 | 54 | mutex_lock(&ch->cdma.lock); |
0b8070d1 | 55 | |
8474b025 MP |
56 | if (show_fifo) |
57 | host1x_hw_show_channel_fifo(m, ch, o); | |
0b8070d1 | 58 | |
8474b025 | 59 | host1x_hw_show_channel_cdma(m, ch, o); |
0b8070d1 | 60 | |
8474b025 | 61 | mutex_unlock(&ch->cdma.lock); |
6236451d TB |
62 | |
63 | return 0; | |
64 | } | |
65 | ||
66 | static void show_syncpts(struct host1x *m, struct output *o) | |
67 | { | |
14c95fc8 | 68 | unsigned int i; |
6df633d0 | 69 | |
6236451d | 70 | host1x_debug_output(o, "---- syncpts ----\n"); |
0b8070d1 | 71 | |
6236451d TB |
72 | for (i = 0; i < host1x_syncpt_nb_pts(m); i++) { |
73 | u32 max = host1x_syncpt_read_max(m->syncpt + i); | |
74 | u32 min = host1x_syncpt_load(m->syncpt + i); | |
6df633d0 | 75 | |
6236451d TB |
76 | if (!min && !max) |
77 | continue; | |
14c95fc8 TR |
78 | |
79 | host1x_debug_output(o, "id %u (%s) min %d max %d\n", | |
6236451d TB |
80 | i, m->syncpt[i].name, min, max); |
81 | } | |
82 | ||
83 | for (i = 0; i < host1x_syncpt_nb_bases(m); i++) { | |
84 | u32 base_val; | |
6df633d0 | 85 | |
6236451d TB |
86 | base_val = host1x_syncpt_load_wait_base(m->syncpt + i); |
87 | if (base_val) | |
14c95fc8 | 88 | host1x_debug_output(o, "waitbase id %u val %d\n", i, |
6236451d TB |
89 | base_val); |
90 | } | |
91 | ||
92 | host1x_debug_output(o, "\n"); | |
93 | } | |
94 | ||
8474b025 | 95 | static void show_all(struct host1x *m, struct output *o, bool show_fifo) |
6236451d | 96 | { |
d4ad3ad9 | 97 | unsigned int i; |
6236451d TB |
98 | |
99 | host1x_hw_show_mlocks(m, o); | |
100 | show_syncpts(m, o); | |
101 | host1x_debug_output(o, "---- channels ----\n"); | |
102 | ||
8474b025 MP |
103 | for (i = 0; i < m->info->nb_channels; ++i) { |
104 | struct host1x_channel *ch = host1x_channel_get_index(m, i); | |
6236451d | 105 | |
8474b025 MP |
106 | if (ch) { |
107 | show_channel(ch, o, show_fifo); | |
108 | host1x_channel_put(ch); | |
109 | } | |
110 | } | |
6236451d TB |
111 | } |
112 | ||
113 | static int host1x_debug_show_all(struct seq_file *s, void *unused) | |
114 | { | |
115 | struct output o = { | |
116 | .fn = write_to_seqfile, | |
117 | .ctx = s | |
118 | }; | |
0b8070d1 | 119 | |
8474b025 | 120 | show_all(s->private, &o, true); |
0b8070d1 | 121 | |
6236451d TB |
122 | return 0; |
123 | } | |
124 | ||
125 | static int host1x_debug_show(struct seq_file *s, void *unused) | |
126 | { | |
127 | struct output o = { | |
128 | .fn = write_to_seqfile, | |
129 | .ctx = s | |
130 | }; | |
0b8070d1 | 131 | |
8474b025 | 132 | show_all(s->private, &o, false); |
0b8070d1 | 133 | |
6236451d TB |
134 | return 0; |
135 | } | |
136 | ||
137 | static int host1x_debug_open_all(struct inode *inode, struct file *file) | |
138 | { | |
139 | return single_open(file, host1x_debug_show_all, inode->i_private); | |
140 | } | |
141 | ||
142 | static const struct file_operations host1x_debug_all_fops = { | |
0b8070d1 TR |
143 | .open = host1x_debug_open_all, |
144 | .read = seq_read, | |
145 | .llseek = seq_lseek, | |
146 | .release = single_release, | |
6236451d TB |
147 | }; |
148 | ||
149 | static int host1x_debug_open(struct inode *inode, struct file *file) | |
150 | { | |
151 | return single_open(file, host1x_debug_show, inode->i_private); | |
152 | } | |
153 | ||
154 | static const struct file_operations host1x_debug_fops = { | |
0b8070d1 TR |
155 | .open = host1x_debug_open, |
156 | .read = seq_read, | |
157 | .llseek = seq_lseek, | |
158 | .release = single_release, | |
6236451d TB |
159 | }; |
160 | ||
8e0d788c | 161 | static void host1x_debugfs_init(struct host1x *host1x) |
6236451d TB |
162 | { |
163 | struct dentry *de = debugfs_create_dir("tegra-host1x", NULL); | |
164 | ||
6236451d TB |
165 | /* Store the created entry */ |
166 | host1x->debugfs = de; | |
167 | ||
168 | debugfs_create_file("status", S_IRUGO, de, host1x, &host1x_debug_fops); | |
169 | debugfs_create_file("status_all", S_IRUGO, de, host1x, | |
170 | &host1x_debug_all_fops); | |
171 | ||
172 | debugfs_create_u32("trace_cmdbuf", S_IRUGO|S_IWUSR, de, | |
173 | &host1x_debug_trace_cmdbuf); | |
174 | ||
175 | host1x_hw_debug_init(host1x, de); | |
176 | ||
177 | debugfs_create_u32("force_timeout_pid", S_IRUGO|S_IWUSR, de, | |
178 | &host1x_debug_force_timeout_pid); | |
179 | debugfs_create_u32("force_timeout_val", S_IRUGO|S_IWUSR, de, | |
180 | &host1x_debug_force_timeout_val); | |
181 | debugfs_create_u32("force_timeout_channel", S_IRUGO|S_IWUSR, de, | |
182 | &host1x_debug_force_timeout_channel); | |
183 | } | |
184 | ||
8e0d788c | 185 | static void host1x_debugfs_exit(struct host1x *host1x) |
6236451d TB |
186 | { |
187 | debugfs_remove_recursive(host1x->debugfs); | |
188 | } | |
8e0d788c | 189 | |
6236451d TB |
190 | void host1x_debug_init(struct host1x *host1x) |
191 | { | |
8e0d788c TR |
192 | if (IS_ENABLED(CONFIG_DEBUG_FS)) |
193 | host1x_debugfs_init(host1x); | |
6236451d | 194 | } |
8e0d788c | 195 | |
6236451d TB |
196 | void host1x_debug_deinit(struct host1x *host1x) |
197 | { | |
8e0d788c TR |
198 | if (IS_ENABLED(CONFIG_DEBUG_FS)) |
199 | host1x_debugfs_exit(host1x); | |
6236451d | 200 | } |
6236451d TB |
201 | |
202 | void host1x_debug_dump(struct host1x *host1x) | |
203 | { | |
204 | struct output o = { | |
205 | .fn = write_to_printk | |
206 | }; | |
0b8070d1 | 207 | |
8474b025 | 208 | show_all(host1x, &o, true); |
6236451d TB |
209 | } |
210 | ||
211 | void host1x_debug_dump_syncpts(struct host1x *host1x) | |
212 | { | |
213 | struct output o = { | |
214 | .fn = write_to_printk | |
215 | }; | |
0b8070d1 | 216 | |
6236451d TB |
217 | show_syncpts(host1x, &o); |
218 | } |