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