diff options
author | Terje Bergstrom <tbergstrom@nvidia.com> | 2013-03-22 10:34:04 -0400 |
---|---|---|
committer | Thierry Reding <thierry.reding@avionic-design.de> | 2013-04-22 06:32:46 -0400 |
commit | 6236451d83a720072053855fa63d51934024a707 (patch) | |
tree | 8596f5ceee4e8b38804a74895d698a389e5cf6bf /drivers/gpu/host1x/debug.c | |
parent | 6579324a41cc414009a601738b70a53d6376325c (diff) |
gpu: host1x: Add debug support
Add support for host1x debugging. Adds debugfs entries, and dumps
channel state to UART in case of stuck job.
Signed-off-by: Arto Merilainen <amerilainen@nvidia.com>
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-by: Thierry Reding <thierry.reding@avionic-design.de>
Tested-by: Thierry Reding <thierry.reding@avionic-design.de>
Tested-by: Erik Faye-Lund <kusmabite@gmail.com>
Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
Diffstat (limited to 'drivers/gpu/host1x/debug.c')
-rw-r--r-- | drivers/gpu/host1x/debug.c | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/drivers/gpu/host1x/debug.c b/drivers/gpu/host1x/debug.c new file mode 100644 index 000000000000..3ec7d77de24d --- /dev/null +++ b/drivers/gpu/host1x/debug.c | |||
@@ -0,0 +1,210 @@ | |||
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 | { | ||
65 | int i; | ||
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; | ||
72 | host1x_debug_output(o, "id %d (%s) min %d max %d\n", | ||
73 | i, m->syncpt[i].name, min, max); | ||
74 | } | ||
75 | |||
76 | for (i = 0; i < host1x_syncpt_nb_bases(m); i++) { | ||
77 | u32 base_val; | ||
78 | base_val = host1x_syncpt_load_wait_base(m->syncpt + i); | ||
79 | if (base_val) | ||
80 | host1x_debug_output(o, "waitbase id %d val %d\n", i, | ||
81 | base_val); | ||
82 | } | ||
83 | |||
84 | host1x_debug_output(o, "\n"); | ||
85 | } | ||
86 | |||
87 | static void show_all(struct host1x *m, struct output *o) | ||
88 | { | ||
89 | struct host1x_channel *ch; | ||
90 | |||
91 | host1x_hw_show_mlocks(m, o); | ||
92 | show_syncpts(m, o); | ||
93 | host1x_debug_output(o, "---- channels ----\n"); | ||
94 | |||
95 | host1x_for_each_channel(m, ch) | ||
96 | show_channels(ch, o, true); | ||
97 | } | ||
98 | |||
99 | #ifdef CONFIG_DEBUG_FS | ||
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 | |||
156 | void host1x_debug_init(struct host1x *host1x) | ||
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 | |||
183 | void host1x_debug_deinit(struct host1x *host1x) | ||
184 | { | ||
185 | debugfs_remove_recursive(host1x->debugfs); | ||
186 | } | ||
187 | #else | ||
188 | void host1x_debug_init(struct host1x *host1x) | ||
189 | { | ||
190 | } | ||
191 | void host1x_debug_deinit(struct host1x *host1x) | ||
192 | { | ||
193 | } | ||
194 | #endif | ||
195 | |||
196 | void host1x_debug_dump(struct host1x *host1x) | ||
197 | { | ||
198 | struct output o = { | ||
199 | .fn = write_to_printk | ||
200 | }; | ||
201 | show_all(host1x, &o); | ||
202 | } | ||
203 | |||
204 | void host1x_debug_dump_syncpts(struct host1x *host1x) | ||
205 | { | ||
206 | struct output o = { | ||
207 | .fn = write_to_printk | ||
208 | }; | ||
209 | show_syncpts(host1x, &o); | ||
210 | } | ||