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 | { | |
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 | ||
6236451d TB |
99 | static void show_all_no_fifo(struct host1x *host1x, struct output *o) |
100 | { | |
101 | struct host1x_channel *ch; | |
102 | ||
103 | host1x_hw_show_mlocks(host1x, o); | |
104 | show_syncpts(host1x, o); | |
105 | host1x_debug_output(o, "---- channels ----\n"); | |
106 | ||
107 | host1x_for_each_channel(host1x, ch) | |
108 | show_channels(ch, o, false); | |
109 | } | |
110 | ||
111 | static int host1x_debug_show_all(struct seq_file *s, void *unused) | |
112 | { | |
113 | struct output o = { | |
114 | .fn = write_to_seqfile, | |
115 | .ctx = s | |
116 | }; | |
117 | show_all(s->private, &o); | |
118 | return 0; | |
119 | } | |
120 | ||
121 | static int host1x_debug_show(struct seq_file *s, void *unused) | |
122 | { | |
123 | struct output o = { | |
124 | .fn = write_to_seqfile, | |
125 | .ctx = s | |
126 | }; | |
127 | show_all_no_fifo(s->private, &o); | |
128 | return 0; | |
129 | } | |
130 | ||
131 | static int host1x_debug_open_all(struct inode *inode, struct file *file) | |
132 | { | |
133 | return single_open(file, host1x_debug_show_all, inode->i_private); | |
134 | } | |
135 | ||
136 | static const struct file_operations host1x_debug_all_fops = { | |
137 | .open = host1x_debug_open_all, | |
138 | .read = seq_read, | |
139 | .llseek = seq_lseek, | |
140 | .release = single_release, | |
141 | }; | |
142 | ||
143 | static int host1x_debug_open(struct inode *inode, struct file *file) | |
144 | { | |
145 | return single_open(file, host1x_debug_show, inode->i_private); | |
146 | } | |
147 | ||
148 | static const struct file_operations host1x_debug_fops = { | |
149 | .open = host1x_debug_open, | |
150 | .read = seq_read, | |
151 | .llseek = seq_lseek, | |
152 | .release = single_release, | |
153 | }; | |
154 | ||
8e0d788c | 155 | static void host1x_debugfs_init(struct host1x *host1x) |
6236451d TB |
156 | { |
157 | struct dentry *de = debugfs_create_dir("tegra-host1x", NULL); | |
158 | ||
159 | if (!de) | |
160 | return; | |
161 | ||
162 | /* Store the created entry */ | |
163 | host1x->debugfs = de; | |
164 | ||
165 | debugfs_create_file("status", S_IRUGO, de, host1x, &host1x_debug_fops); | |
166 | debugfs_create_file("status_all", S_IRUGO, de, host1x, | |
167 | &host1x_debug_all_fops); | |
168 | ||
169 | debugfs_create_u32("trace_cmdbuf", S_IRUGO|S_IWUSR, de, | |
170 | &host1x_debug_trace_cmdbuf); | |
171 | ||
172 | host1x_hw_debug_init(host1x, de); | |
173 | ||
174 | debugfs_create_u32("force_timeout_pid", S_IRUGO|S_IWUSR, de, | |
175 | &host1x_debug_force_timeout_pid); | |
176 | debugfs_create_u32("force_timeout_val", S_IRUGO|S_IWUSR, de, | |
177 | &host1x_debug_force_timeout_val); | |
178 | debugfs_create_u32("force_timeout_channel", S_IRUGO|S_IWUSR, de, | |
179 | &host1x_debug_force_timeout_channel); | |
180 | } | |
181 | ||
8e0d788c | 182 | static void host1x_debugfs_exit(struct host1x *host1x) |
6236451d TB |
183 | { |
184 | debugfs_remove_recursive(host1x->debugfs); | |
185 | } | |
8e0d788c | 186 | |
6236451d TB |
187 | void host1x_debug_init(struct host1x *host1x) |
188 | { | |
8e0d788c TR |
189 | if (IS_ENABLED(CONFIG_DEBUG_FS)) |
190 | host1x_debugfs_init(host1x); | |
6236451d | 191 | } |
8e0d788c | 192 | |
6236451d TB |
193 | void host1x_debug_deinit(struct host1x *host1x) |
194 | { | |
8e0d788c TR |
195 | if (IS_ENABLED(CONFIG_DEBUG_FS)) |
196 | host1x_debugfs_exit(host1x); | |
6236451d | 197 | } |
6236451d TB |
198 | |
199 | void host1x_debug_dump(struct host1x *host1x) | |
200 | { | |
201 | struct output o = { | |
202 | .fn = write_to_printk | |
203 | }; | |
204 | show_all(host1x, &o); | |
205 | } | |
206 | ||
207 | void host1x_debug_dump_syncpts(struct host1x *host1x) | |
208 | { | |
209 | struct output o = { | |
210 | .fn = write_to_printk | |
211 | }; | |
212 | show_syncpts(host1x, &o); | |
213 | } |