]>
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; |
6df633d0 | 66 | |
6236451d TB |
67 | host1x_debug_output(o, "---- syncpts ----\n"); |
68 | for (i = 0; i < host1x_syncpt_nb_pts(m); i++) { | |
69 | u32 max = host1x_syncpt_read_max(m->syncpt + i); | |
70 | u32 min = host1x_syncpt_load(m->syncpt + i); | |
6df633d0 | 71 | |
6236451d TB |
72 | if (!min && !max) |
73 | continue; | |
14c95fc8 TR |
74 | |
75 | host1x_debug_output(o, "id %u (%s) min %d max %d\n", | |
6236451d TB |
76 | i, m->syncpt[i].name, min, max); |
77 | } | |
78 | ||
79 | for (i = 0; i < host1x_syncpt_nb_bases(m); i++) { | |
80 | u32 base_val; | |
6df633d0 | 81 | |
6236451d TB |
82 | base_val = host1x_syncpt_load_wait_base(m->syncpt + i); |
83 | if (base_val) | |
14c95fc8 | 84 | host1x_debug_output(o, "waitbase id %u val %d\n", i, |
6236451d TB |
85 | base_val); |
86 | } | |
87 | ||
88 | host1x_debug_output(o, "\n"); | |
89 | } | |
90 | ||
91 | static void show_all(struct host1x *m, struct output *o) | |
92 | { | |
93 | struct host1x_channel *ch; | |
94 | ||
95 | host1x_hw_show_mlocks(m, o); | |
96 | show_syncpts(m, o); | |
97 | host1x_debug_output(o, "---- channels ----\n"); | |
98 | ||
99 | host1x_for_each_channel(m, ch) | |
100 | show_channels(ch, o, true); | |
101 | } | |
102 | ||
6236451d TB |
103 | static void show_all_no_fifo(struct host1x *host1x, struct output *o) |
104 | { | |
105 | struct host1x_channel *ch; | |
106 | ||
107 | host1x_hw_show_mlocks(host1x, o); | |
108 | show_syncpts(host1x, o); | |
109 | host1x_debug_output(o, "---- channels ----\n"); | |
110 | ||
111 | host1x_for_each_channel(host1x, ch) | |
112 | show_channels(ch, o, false); | |
113 | } | |
114 | ||
115 | static int host1x_debug_show_all(struct seq_file *s, void *unused) | |
116 | { | |
117 | struct output o = { | |
118 | .fn = write_to_seqfile, | |
119 | .ctx = s | |
120 | }; | |
121 | show_all(s->private, &o); | |
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 | }; | |
131 | show_all_no_fifo(s->private, &o); | |
132 | return 0; | |
133 | } | |
134 | ||
135 | static int host1x_debug_open_all(struct inode *inode, struct file *file) | |
136 | { | |
137 | return single_open(file, host1x_debug_show_all, inode->i_private); | |
138 | } | |
139 | ||
140 | static const struct file_operations host1x_debug_all_fops = { | |
141 | .open = host1x_debug_open_all, | |
142 | .read = seq_read, | |
143 | .llseek = seq_lseek, | |
144 | .release = single_release, | |
145 | }; | |
146 | ||
147 | static int host1x_debug_open(struct inode *inode, struct file *file) | |
148 | { | |
149 | return single_open(file, host1x_debug_show, inode->i_private); | |
150 | } | |
151 | ||
152 | static const struct file_operations host1x_debug_fops = { | |
153 | .open = host1x_debug_open, | |
154 | .read = seq_read, | |
155 | .llseek = seq_lseek, | |
156 | .release = single_release, | |
157 | }; | |
158 | ||
8e0d788c | 159 | static void host1x_debugfs_init(struct host1x *host1x) |
6236451d TB |
160 | { |
161 | struct dentry *de = debugfs_create_dir("tegra-host1x", NULL); | |
162 | ||
163 | if (!de) | |
164 | return; | |
165 | ||
166 | /* Store the created entry */ | |
167 | host1x->debugfs = de; | |
168 | ||
169 | debugfs_create_file("status", S_IRUGO, de, host1x, &host1x_debug_fops); | |
170 | debugfs_create_file("status_all", S_IRUGO, de, host1x, | |
171 | &host1x_debug_all_fops); | |
172 | ||
173 | debugfs_create_u32("trace_cmdbuf", S_IRUGO|S_IWUSR, de, | |
174 | &host1x_debug_trace_cmdbuf); | |
175 | ||
176 | host1x_hw_debug_init(host1x, de); | |
177 | ||
178 | debugfs_create_u32("force_timeout_pid", S_IRUGO|S_IWUSR, de, | |
179 | &host1x_debug_force_timeout_pid); | |
180 | debugfs_create_u32("force_timeout_val", S_IRUGO|S_IWUSR, de, | |
181 | &host1x_debug_force_timeout_val); | |
182 | debugfs_create_u32("force_timeout_channel", S_IRUGO|S_IWUSR, de, | |
183 | &host1x_debug_force_timeout_channel); | |
184 | } | |
185 | ||
8e0d788c | 186 | static void host1x_debugfs_exit(struct host1x *host1x) |
6236451d TB |
187 | { |
188 | debugfs_remove_recursive(host1x->debugfs); | |
189 | } | |
8e0d788c | 190 | |
6236451d TB |
191 | void host1x_debug_init(struct host1x *host1x) |
192 | { | |
8e0d788c TR |
193 | if (IS_ENABLED(CONFIG_DEBUG_FS)) |
194 | host1x_debugfs_init(host1x); | |
6236451d | 195 | } |
8e0d788c | 196 | |
6236451d TB |
197 | void host1x_debug_deinit(struct host1x *host1x) |
198 | { | |
8e0d788c TR |
199 | if (IS_ENABLED(CONFIG_DEBUG_FS)) |
200 | host1x_debugfs_exit(host1x); | |
6236451d | 201 | } |
6236451d TB |
202 | |
203 | void host1x_debug_dump(struct host1x *host1x) | |
204 | { | |
205 | struct output o = { | |
206 | .fn = write_to_printk | |
207 | }; | |
208 | show_all(host1x, &o); | |
209 | } | |
210 | ||
211 | void host1x_debug_dump_syncpts(struct host1x *host1x) | |
212 | { | |
213 | struct output o = { | |
214 | .fn = write_to_printk | |
215 | }; | |
216 | show_syncpts(host1x, &o); | |
217 | } |