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 | |
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>
-rw-r--r-- | drivers/gpu/host1x/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/host1x/cdma.c | 4 | ||||
-rw-r--r-- | drivers/gpu/host1x/debug.c | 210 | ||||
-rw-r--r-- | drivers/gpu/host1x/debug.h | 51 | ||||
-rw-r--r-- | drivers/gpu/host1x/dev.c | 3 | ||||
-rw-r--r-- | drivers/gpu/host1x/dev.h | 42 | ||||
-rw-r--r-- | drivers/gpu/host1x/hw/cdma_hw.c | 2 | ||||
-rw-r--r-- | drivers/gpu/host1x/hw/channel_hw.c | 25 | ||||
-rw-r--r-- | drivers/gpu/host1x/hw/debug_hw.c | 322 | ||||
-rw-r--r-- | drivers/gpu/host1x/hw/host1x01.c | 2 | ||||
-rw-r--r-- | drivers/gpu/host1x/hw/hw_host1x01_channel.h | 18 | ||||
-rw-r--r-- | drivers/gpu/host1x/hw/hw_host1x01_sync.h | 115 | ||||
-rw-r--r-- | drivers/gpu/host1x/hw/hw_host1x01_uclass.h | 6 | ||||
-rw-r--r-- | drivers/gpu/host1x/hw/syncpt_hw.c | 1 | ||||
-rw-r--r-- | drivers/gpu/host1x/syncpt.c | 5 |
15 files changed, 807 insertions, 0 deletions
diff --git a/drivers/gpu/host1x/Makefile b/drivers/gpu/host1x/Makefile index 06a995b60902..49fd5807b0e7 100644 --- a/drivers/gpu/host1x/Makefile +++ b/drivers/gpu/host1x/Makefile | |||
@@ -7,6 +7,7 @@ host1x-y = \ | |||
7 | cdma.o \ | 7 | cdma.o \ |
8 | channel.o \ | 8 | channel.o \ |
9 | job.o \ | 9 | job.o \ |
10 | debug.o \ | ||
10 | hw/host1x01.o | 11 | hw/host1x01.o |
11 | 12 | ||
12 | obj-$(CONFIG_TEGRA_HOST1X) += host1x.o | 13 | obj-$(CONFIG_TEGRA_HOST1X) += host1x.o |
diff --git a/drivers/gpu/host1x/cdma.c b/drivers/gpu/host1x/cdma.c index 33935de91bb1..de72172d3b5f 100644 --- a/drivers/gpu/host1x/cdma.c +++ b/drivers/gpu/host1x/cdma.c | |||
@@ -439,6 +439,10 @@ void host1x_cdma_push(struct host1x_cdma *cdma, u32 op1, u32 op2) | |||
439 | struct push_buffer *pb = &cdma->push_buffer; | 439 | struct push_buffer *pb = &cdma->push_buffer; |
440 | u32 slots_free = cdma->slots_free; | 440 | u32 slots_free = cdma->slots_free; |
441 | 441 | ||
442 | if (host1x_debug_trace_cmdbuf) | ||
443 | trace_host1x_cdma_push(dev_name(cdma_to_channel(cdma)->dev), | ||
444 | op1, op2); | ||
445 | |||
442 | if (slots_free == 0) { | 446 | if (slots_free == 0) { |
443 | host1x_hw_cdma_flush(host1x, cdma); | 447 | host1x_hw_cdma_flush(host1x, cdma); |
444 | slots_free = host1x_cdma_wait_locked(cdma, | 448 | slots_free = host1x_cdma_wait_locked(cdma, |
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 | } | ||
diff --git a/drivers/gpu/host1x/debug.h b/drivers/gpu/host1x/debug.h new file mode 100644 index 000000000000..4595b2e0799f --- /dev/null +++ b/drivers/gpu/host1x/debug.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * Tegra host1x Debug | ||
3 | * | ||
4 | * Copyright (c) 2011-2013 NVIDIA Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #ifndef __HOST1X_DEBUG_H | ||
19 | #define __HOST1X_DEBUG_H | ||
20 | |||
21 | #include <linux/debugfs.h> | ||
22 | #include <linux/seq_file.h> | ||
23 | |||
24 | struct host1x; | ||
25 | |||
26 | struct output { | ||
27 | void (*fn)(void *ctx, const char *str, size_t len); | ||
28 | void *ctx; | ||
29 | char buf[256]; | ||
30 | }; | ||
31 | |||
32 | static inline void write_to_seqfile(void *ctx, const char *str, size_t len) | ||
33 | { | ||
34 | seq_write((struct seq_file *)ctx, str, len); | ||
35 | } | ||
36 | |||
37 | static inline void write_to_printk(void *ctx, const char *str, size_t len) | ||
38 | { | ||
39 | pr_info("%s", str); | ||
40 | } | ||
41 | |||
42 | void __printf(2, 3) host1x_debug_output(struct output *o, const char *fmt, ...); | ||
43 | |||
44 | extern unsigned int host1x_debug_trace_cmdbuf; | ||
45 | |||
46 | void host1x_debug_init(struct host1x *host1x); | ||
47 | void host1x_debug_deinit(struct host1x *host1x); | ||
48 | void host1x_debug_dump(struct host1x *host1x); | ||
49 | void host1x_debug_dump_syncpts(struct host1x *host1x); | ||
50 | |||
51 | #endif | ||
diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index 4e522c532bc8..96897242fcc2 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include "dev.h" | 30 | #include "dev.h" |
31 | #include "intr.h" | 31 | #include "intr.h" |
32 | #include "channel.h" | 32 | #include "channel.h" |
33 | #include "debug.h" | ||
33 | #include "hw/host1x01.h" | 34 | #include "hw/host1x01.h" |
34 | 35 | ||
35 | void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r) | 36 | void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r) |
@@ -147,6 +148,8 @@ static int host1x_probe(struct platform_device *pdev) | |||
147 | goto fail_deinit_syncpt; | 148 | goto fail_deinit_syncpt; |
148 | } | 149 | } |
149 | 150 | ||
151 | host1x_debug_init(host); | ||
152 | |||
150 | return 0; | 153 | return 0; |
151 | 154 | ||
152 | fail_deinit_syncpt: | 155 | fail_deinit_syncpt: |
diff --git a/drivers/gpu/host1x/dev.h b/drivers/gpu/host1x/dev.h index 1a9b4383dc3b..4d16fe92400a 100644 --- a/drivers/gpu/host1x/dev.h +++ b/drivers/gpu/host1x/dev.h | |||
@@ -31,6 +31,8 @@ struct host1x_channel; | |||
31 | struct host1x_cdma; | 31 | struct host1x_cdma; |
32 | struct host1x_job; | 32 | struct host1x_job; |
33 | struct push_buffer; | 33 | struct push_buffer; |
34 | struct output; | ||
35 | struct dentry; | ||
34 | 36 | ||
35 | struct host1x_channel_ops { | 37 | struct host1x_channel_ops { |
36 | int (*init)(struct host1x_channel *channel, struct host1x *host, | 38 | int (*init)(struct host1x_channel *channel, struct host1x *host, |
@@ -54,6 +56,18 @@ struct host1x_pushbuffer_ops { | |||
54 | void (*init)(struct push_buffer *pb); | 56 | void (*init)(struct push_buffer *pb); |
55 | }; | 57 | }; |
56 | 58 | ||
59 | struct host1x_debug_ops { | ||
60 | void (*debug_init)(struct dentry *de); | ||
61 | void (*show_channel_cdma)(struct host1x *host, | ||
62 | struct host1x_channel *ch, | ||
63 | struct output *o); | ||
64 | void (*show_channel_fifo)(struct host1x *host, | ||
65 | struct host1x_channel *ch, | ||
66 | struct output *o); | ||
67 | void (*show_mlocks)(struct host1x *host, struct output *output); | ||
68 | |||
69 | }; | ||
70 | |||
57 | struct host1x_syncpt_ops { | 71 | struct host1x_syncpt_ops { |
58 | void (*restore)(struct host1x_syncpt *syncpt); | 72 | void (*restore)(struct host1x_syncpt *syncpt); |
59 | void (*restore_wait_base)(struct host1x_syncpt *syncpt); | 73 | void (*restore_wait_base)(struct host1x_syncpt *syncpt); |
@@ -100,6 +114,7 @@ struct host1x { | |||
100 | const struct host1x_channel_ops *channel_op; | 114 | const struct host1x_channel_ops *channel_op; |
101 | const struct host1x_cdma_ops *cdma_op; | 115 | const struct host1x_cdma_ops *cdma_op; |
102 | const struct host1x_pushbuffer_ops *cdma_pb_op; | 116 | const struct host1x_pushbuffer_ops *cdma_pb_op; |
117 | const struct host1x_debug_ops *debug_op; | ||
103 | 118 | ||
104 | struct host1x_syncpt *nop_sp; | 119 | struct host1x_syncpt *nop_sp; |
105 | 120 | ||
@@ -107,6 +122,8 @@ struct host1x { | |||
107 | struct host1x_channel chlist; | 122 | struct host1x_channel chlist; |
108 | unsigned long allocated_channels; | 123 | unsigned long allocated_channels; |
109 | unsigned int num_allocated_channels; | 124 | unsigned int num_allocated_channels; |
125 | |||
126 | struct dentry *debugfs; | ||
110 | }; | 127 | }; |
111 | 128 | ||
112 | void host1x_sync_writel(struct host1x *host1x, u32 r, u32 v); | 129 | void host1x_sync_writel(struct host1x *host1x, u32 r, u32 v); |
@@ -257,4 +274,29 @@ static inline void host1x_hw_pushbuffer_init(struct host1x *host, | |||
257 | host->cdma_pb_op->init(pb); | 274 | host->cdma_pb_op->init(pb); |
258 | } | 275 | } |
259 | 276 | ||
277 | static inline void host1x_hw_debug_init(struct host1x *host, struct dentry *de) | ||
278 | { | ||
279 | if (host->debug_op && host->debug_op->debug_init) | ||
280 | host->debug_op->debug_init(de); | ||
281 | } | ||
282 | |||
283 | static inline void host1x_hw_show_channel_cdma(struct host1x *host, | ||
284 | struct host1x_channel *channel, | ||
285 | struct output *o) | ||
286 | { | ||
287 | host->debug_op->show_channel_cdma(host, channel, o); | ||
288 | } | ||
289 | |||
290 | static inline void host1x_hw_show_channel_fifo(struct host1x *host, | ||
291 | struct host1x_channel *channel, | ||
292 | struct output *o) | ||
293 | { | ||
294 | host->debug_op->show_channel_fifo(host, channel, o); | ||
295 | } | ||
296 | |||
297 | static inline void host1x_hw_show_mlocks(struct host1x *host, struct output *o) | ||
298 | { | ||
299 | host->debug_op->show_mlocks(host, o); | ||
300 | } | ||
301 | |||
260 | #endif | 302 | #endif |
diff --git a/drivers/gpu/host1x/hw/cdma_hw.c b/drivers/gpu/host1x/hw/cdma_hw.c index 4eb22ef29776..590b69d91dab 100644 --- a/drivers/gpu/host1x/hw/cdma_hw.c +++ b/drivers/gpu/host1x/hw/cdma_hw.c | |||
@@ -244,6 +244,8 @@ static void cdma_timeout_handler(struct work_struct *work) | |||
244 | host1x = cdma_to_host1x(cdma); | 244 | host1x = cdma_to_host1x(cdma); |
245 | ch = cdma_to_channel(cdma); | 245 | ch = cdma_to_channel(cdma); |
246 | 246 | ||
247 | host1x_debug_dump(cdma_to_host1x(cdma)); | ||
248 | |||
247 | mutex_lock(&cdma->lock); | 249 | mutex_lock(&cdma->lock); |
248 | 250 | ||
249 | if (!cdma->timeout.client) { | 251 | if (!cdma->timeout.client) { |
diff --git a/drivers/gpu/host1x/hw/channel_hw.c b/drivers/gpu/host1x/hw/channel_hw.c index 5137a5604215..ee199623e365 100644 --- a/drivers/gpu/host1x/hw/channel_hw.c +++ b/drivers/gpu/host1x/hw/channel_hw.c | |||
@@ -29,6 +29,30 @@ | |||
29 | #define HOST1X_CHANNEL_SIZE 16384 | 29 | #define HOST1X_CHANNEL_SIZE 16384 |
30 | #define TRACE_MAX_LENGTH 128U | 30 | #define TRACE_MAX_LENGTH 128U |
31 | 31 | ||
32 | static void trace_write_gather(struct host1x_cdma *cdma, struct host1x_bo *bo, | ||
33 | u32 offset, u32 words) | ||
34 | { | ||
35 | void *mem = NULL; | ||
36 | |||
37 | if (host1x_debug_trace_cmdbuf) | ||
38 | mem = host1x_bo_mmap(bo); | ||
39 | |||
40 | if (mem) { | ||
41 | u32 i; | ||
42 | /* | ||
43 | * Write in batches of 128 as there seems to be a limit | ||
44 | * of how much you can output to ftrace at once. | ||
45 | */ | ||
46 | for (i = 0; i < words; i += TRACE_MAX_LENGTH) { | ||
47 | trace_host1x_cdma_push_gather( | ||
48 | dev_name(cdma_to_channel(cdma)->dev), | ||
49 | (u32)bo, min(words - i, TRACE_MAX_LENGTH), | ||
50 | offset + i * sizeof(u32), mem); | ||
51 | } | ||
52 | host1x_bo_munmap(bo, mem); | ||
53 | } | ||
54 | } | ||
55 | |||
32 | static void submit_gathers(struct host1x_job *job) | 56 | static void submit_gathers(struct host1x_job *job) |
33 | { | 57 | { |
34 | struct host1x_cdma *cdma = &job->channel->cdma; | 58 | struct host1x_cdma *cdma = &job->channel->cdma; |
@@ -38,6 +62,7 @@ static void submit_gathers(struct host1x_job *job) | |||
38 | struct host1x_job_gather *g = &job->gathers[i]; | 62 | struct host1x_job_gather *g = &job->gathers[i]; |
39 | u32 op1 = host1x_opcode_gather(g->words); | 63 | u32 op1 = host1x_opcode_gather(g->words); |
40 | u32 op2 = g->base + g->offset; | 64 | u32 op2 = g->base + g->offset; |
65 | trace_write_gather(cdma, g->bo, g->offset, op1 & 0xffff); | ||
41 | host1x_cdma_push(cdma, op1, op2); | 66 | host1x_cdma_push(cdma, op1, op2); |
42 | } | 67 | } |
43 | } | 68 | } |
diff --git a/drivers/gpu/host1x/hw/debug_hw.c b/drivers/gpu/host1x/hw/debug_hw.c new file mode 100644 index 000000000000..334c038052f5 --- /dev/null +++ b/drivers/gpu/host1x/hw/debug_hw.c | |||
@@ -0,0 +1,322 @@ | |||
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/mm.h> | ||
21 | #include <linux/scatterlist.h> | ||
22 | |||
23 | #include <linux/io.h> | ||
24 | |||
25 | #include "dev.h" | ||
26 | #include "debug.h" | ||
27 | #include "cdma.h" | ||
28 | #include "channel.h" | ||
29 | #include "host1x_bo.h" | ||
30 | |||
31 | #define HOST1X_DEBUG_MAX_PAGE_OFFSET 102400 | ||
32 | |||
33 | enum { | ||
34 | HOST1X_OPCODE_SETCLASS = 0x00, | ||
35 | HOST1X_OPCODE_INCR = 0x01, | ||
36 | HOST1X_OPCODE_NONINCR = 0x02, | ||
37 | HOST1X_OPCODE_MASK = 0x03, | ||
38 | HOST1X_OPCODE_IMM = 0x04, | ||
39 | HOST1X_OPCODE_RESTART = 0x05, | ||
40 | HOST1X_OPCODE_GATHER = 0x06, | ||
41 | HOST1X_OPCODE_EXTEND = 0x0e, | ||
42 | }; | ||
43 | |||
44 | enum { | ||
45 | HOST1X_OPCODE_EXTEND_ACQUIRE_MLOCK = 0x00, | ||
46 | HOST1X_OPCODE_EXTEND_RELEASE_MLOCK = 0x01, | ||
47 | }; | ||
48 | |||
49 | static unsigned int show_channel_command(struct output *o, u32 val) | ||
50 | { | ||
51 | unsigned mask; | ||
52 | unsigned subop; | ||
53 | |||
54 | switch (val >> 28) { | ||
55 | case HOST1X_OPCODE_SETCLASS: | ||
56 | mask = val & 0x3f; | ||
57 | if (mask) { | ||
58 | host1x_debug_output(o, "SETCL(class=%03x, offset=%03x, mask=%02x, [", | ||
59 | val >> 6 & 0x3ff, | ||
60 | val >> 16 & 0xfff, mask); | ||
61 | return hweight8(mask); | ||
62 | } else { | ||
63 | host1x_debug_output(o, "SETCL(class=%03x)\n", | ||
64 | val >> 6 & 0x3ff); | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | case HOST1X_OPCODE_INCR: | ||
69 | host1x_debug_output(o, "INCR(offset=%03x, [", | ||
70 | val >> 16 & 0xfff); | ||
71 | return val & 0xffff; | ||
72 | |||
73 | case HOST1X_OPCODE_NONINCR: | ||
74 | host1x_debug_output(o, "NONINCR(offset=%03x, [", | ||
75 | val >> 16 & 0xfff); | ||
76 | return val & 0xffff; | ||
77 | |||
78 | case HOST1X_OPCODE_MASK: | ||
79 | mask = val & 0xffff; | ||
80 | host1x_debug_output(o, "MASK(offset=%03x, mask=%03x, [", | ||
81 | val >> 16 & 0xfff, mask); | ||
82 | return hweight16(mask); | ||
83 | |||
84 | case HOST1X_OPCODE_IMM: | ||
85 | host1x_debug_output(o, "IMM(offset=%03x, data=%03x)\n", | ||
86 | val >> 16 & 0xfff, val & 0xffff); | ||
87 | return 0; | ||
88 | |||
89 | case HOST1X_OPCODE_RESTART: | ||
90 | host1x_debug_output(o, "RESTART(offset=%08x)\n", val << 4); | ||
91 | return 0; | ||
92 | |||
93 | case HOST1X_OPCODE_GATHER: | ||
94 | host1x_debug_output(o, "GATHER(offset=%03x, insert=%d, type=%d, count=%04x, addr=[", | ||
95 | val >> 16 & 0xfff, val >> 15 & 0x1, | ||
96 | val >> 14 & 0x1, val & 0x3fff); | ||
97 | return 1; | ||
98 | |||
99 | case HOST1X_OPCODE_EXTEND: | ||
100 | subop = val >> 24 & 0xf; | ||
101 | if (subop == HOST1X_OPCODE_EXTEND_ACQUIRE_MLOCK) | ||
102 | host1x_debug_output(o, "ACQUIRE_MLOCK(index=%d)\n", | ||
103 | val & 0xff); | ||
104 | else if (subop == HOST1X_OPCODE_EXTEND_RELEASE_MLOCK) | ||
105 | host1x_debug_output(o, "RELEASE_MLOCK(index=%d)\n", | ||
106 | val & 0xff); | ||
107 | else | ||
108 | host1x_debug_output(o, "EXTEND_UNKNOWN(%08x)\n", val); | ||
109 | return 0; | ||
110 | |||
111 | default: | ||
112 | return 0; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | static void show_gather(struct output *o, phys_addr_t phys_addr, | ||
117 | unsigned int words, struct host1x_cdma *cdma, | ||
118 | phys_addr_t pin_addr, u32 *map_addr) | ||
119 | { | ||
120 | /* Map dmaget cursor to corresponding mem handle */ | ||
121 | u32 offset = phys_addr - pin_addr; | ||
122 | unsigned int data_count = 0, i; | ||
123 | |||
124 | /* | ||
125 | * Sometimes we're given different hardware address to the same | ||
126 | * page - in these cases the offset will get an invalid number and | ||
127 | * we just have to bail out. | ||
128 | */ | ||
129 | if (offset > HOST1X_DEBUG_MAX_PAGE_OFFSET) { | ||
130 | host1x_debug_output(o, "[address mismatch]\n"); | ||
131 | return; | ||
132 | } | ||
133 | |||
134 | for (i = 0; i < words; i++) { | ||
135 | u32 addr = phys_addr + i * 4; | ||
136 | u32 val = *(map_addr + offset / 4 + i); | ||
137 | |||
138 | if (!data_count) { | ||
139 | host1x_debug_output(o, "%08x: %08x:", addr, val); | ||
140 | data_count = show_channel_command(o, val); | ||
141 | } else { | ||
142 | host1x_debug_output(o, "%08x%s", val, | ||
143 | data_count > 0 ? ", " : "])\n"); | ||
144 | data_count--; | ||
145 | } | ||
146 | } | ||
147 | } | ||
148 | |||
149 | static void show_channel_gathers(struct output *o, struct host1x_cdma *cdma) | ||
150 | { | ||
151 | struct host1x_job *job; | ||
152 | |||
153 | list_for_each_entry(job, &cdma->sync_queue, list) { | ||
154 | int i; | ||
155 | host1x_debug_output(o, "\n%p: JOB, syncpt_id=%d, syncpt_val=%d, first_get=%08x, timeout=%d num_slots=%d, num_handles=%d\n", | ||
156 | job, job->syncpt_id, job->syncpt_end, | ||
157 | job->first_get, job->timeout, | ||
158 | job->num_slots, job->num_unpins); | ||
159 | |||
160 | for (i = 0; i < job->num_gathers; i++) { | ||
161 | struct host1x_job_gather *g = &job->gathers[i]; | ||
162 | u32 *mapped; | ||
163 | |||
164 | if (job->gather_copy_mapped) | ||
165 | mapped = (u32 *)job->gather_copy_mapped; | ||
166 | else | ||
167 | mapped = host1x_bo_mmap(g->bo); | ||
168 | |||
169 | if (!mapped) { | ||
170 | host1x_debug_output(o, "[could not mmap]\n"); | ||
171 | continue; | ||
172 | } | ||
173 | |||
174 | host1x_debug_output(o, " GATHER at %08x+%04x, %d words\n", | ||
175 | g->base, g->offset, g->words); | ||
176 | |||
177 | show_gather(o, g->base + g->offset, g->words, cdma, | ||
178 | g->base, mapped); | ||
179 | |||
180 | if (!job->gather_copy_mapped) | ||
181 | host1x_bo_munmap(g->bo, mapped); | ||
182 | } | ||
183 | } | ||
184 | } | ||
185 | |||
186 | static void host1x_debug_show_channel_cdma(struct host1x *host, | ||
187 | struct host1x_channel *ch, | ||
188 | struct output *o) | ||
189 | { | ||
190 | struct host1x_cdma *cdma = &ch->cdma; | ||
191 | u32 dmaput, dmaget, dmactrl; | ||
192 | u32 cbstat, cbread; | ||
193 | u32 val, base, baseval; | ||
194 | |||
195 | dmaput = host1x_ch_readl(ch, HOST1X_CHANNEL_DMAPUT); | ||
196 | dmaget = host1x_ch_readl(ch, HOST1X_CHANNEL_DMAGET); | ||
197 | dmactrl = host1x_ch_readl(ch, HOST1X_CHANNEL_DMACTRL); | ||
198 | cbread = host1x_sync_readl(host, HOST1X_SYNC_CBREAD(ch->id)); | ||
199 | cbstat = host1x_sync_readl(host, HOST1X_SYNC_CBSTAT(ch->id)); | ||
200 | |||
201 | host1x_debug_output(o, "%d-%s: ", ch->id, dev_name(ch->dev)); | ||
202 | |||
203 | if (HOST1X_CHANNEL_DMACTRL_DMASTOP_V(dmactrl) || | ||
204 | !ch->cdma.push_buffer.mapped) { | ||
205 | host1x_debug_output(o, "inactive\n\n"); | ||
206 | return; | ||
207 | } | ||
208 | |||
209 | if (HOST1X_SYNC_CBSTAT_CBCLASS_V(cbstat) == HOST1X_CLASS_HOST1X && | ||
210 | HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat) == | ||
211 | HOST1X_UCLASS_WAIT_SYNCPT) | ||
212 | host1x_debug_output(o, "waiting on syncpt %d val %d\n", | ||
213 | cbread >> 24, cbread & 0xffffff); | ||
214 | else if (HOST1X_SYNC_CBSTAT_CBCLASS_V(cbstat) == | ||
215 | HOST1X_CLASS_HOST1X && | ||
216 | HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat) == | ||
217 | HOST1X_UCLASS_WAIT_SYNCPT_BASE) { | ||
218 | |||
219 | base = (cbread >> 16) & 0xff; | ||
220 | baseval = | ||
221 | host1x_sync_readl(host, HOST1X_SYNC_SYNCPT_BASE(base)); | ||
222 | val = cbread & 0xffff; | ||
223 | host1x_debug_output(o, "waiting on syncpt %d val %d (base %d = %d; offset = %d)\n", | ||
224 | cbread >> 24, baseval + val, base, | ||
225 | baseval, val); | ||
226 | } else | ||
227 | host1x_debug_output(o, "active class %02x, offset %04x, val %08x\n", | ||
228 | HOST1X_SYNC_CBSTAT_CBCLASS_V(cbstat), | ||
229 | HOST1X_SYNC_CBSTAT_CBOFFSET_V(cbstat), | ||
230 | cbread); | ||
231 | |||
232 | host1x_debug_output(o, "DMAPUT %08x, DMAGET %08x, DMACTL %08x\n", | ||
233 | dmaput, dmaget, dmactrl); | ||
234 | host1x_debug_output(o, "CBREAD %08x, CBSTAT %08x\n", cbread, cbstat); | ||
235 | |||
236 | show_channel_gathers(o, cdma); | ||
237 | host1x_debug_output(o, "\n"); | ||
238 | } | ||
239 | |||
240 | static void host1x_debug_show_channel_fifo(struct host1x *host, | ||
241 | struct host1x_channel *ch, | ||
242 | struct output *o) | ||
243 | { | ||
244 | u32 val, rd_ptr, wr_ptr, start, end; | ||
245 | unsigned int data_count = 0; | ||
246 | |||
247 | host1x_debug_output(o, "%d: fifo:\n", ch->id); | ||
248 | |||
249 | val = host1x_ch_readl(ch, HOST1X_CHANNEL_FIFOSTAT); | ||
250 | host1x_debug_output(o, "FIFOSTAT %08x\n", val); | ||
251 | if (HOST1X_CHANNEL_FIFOSTAT_CFEMPTY_V(val)) { | ||
252 | host1x_debug_output(o, "[empty]\n"); | ||
253 | return; | ||
254 | } | ||
255 | |||
256 | host1x_sync_writel(host, 0x0, HOST1X_SYNC_CFPEEK_CTRL); | ||
257 | host1x_sync_writel(host, HOST1X_SYNC_CFPEEK_CTRL_ENA_F(1) | | ||
258 | HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(ch->id), | ||
259 | HOST1X_SYNC_CFPEEK_CTRL); | ||
260 | |||
261 | val = host1x_sync_readl(host, HOST1X_SYNC_CFPEEK_PTRS); | ||
262 | rd_ptr = HOST1X_SYNC_CFPEEK_PTRS_CF_RD_PTR_V(val); | ||
263 | wr_ptr = HOST1X_SYNC_CFPEEK_PTRS_CF_WR_PTR_V(val); | ||
264 | |||
265 | val = host1x_sync_readl(host, HOST1X_SYNC_CF_SETUP(ch->id)); | ||
266 | start = HOST1X_SYNC_CF_SETUP_BASE_V(val); | ||
267 | end = HOST1X_SYNC_CF_SETUP_LIMIT_V(val); | ||
268 | |||
269 | do { | ||
270 | host1x_sync_writel(host, 0x0, HOST1X_SYNC_CFPEEK_CTRL); | ||
271 | host1x_sync_writel(host, HOST1X_SYNC_CFPEEK_CTRL_ENA_F(1) | | ||
272 | HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(ch->id) | | ||
273 | HOST1X_SYNC_CFPEEK_CTRL_ADDR_F(rd_ptr), | ||
274 | HOST1X_SYNC_CFPEEK_CTRL); | ||
275 | val = host1x_sync_readl(host, HOST1X_SYNC_CFPEEK_READ); | ||
276 | |||
277 | if (!data_count) { | ||
278 | host1x_debug_output(o, "%08x:", val); | ||
279 | data_count = show_channel_command(o, val); | ||
280 | } else { | ||
281 | host1x_debug_output(o, "%08x%s", val, | ||
282 | data_count > 0 ? ", " : "])\n"); | ||
283 | data_count--; | ||
284 | } | ||
285 | |||
286 | if (rd_ptr == end) | ||
287 | rd_ptr = start; | ||
288 | else | ||
289 | rd_ptr++; | ||
290 | } while (rd_ptr != wr_ptr); | ||
291 | |||
292 | if (data_count) | ||
293 | host1x_debug_output(o, ", ...])\n"); | ||
294 | host1x_debug_output(o, "\n"); | ||
295 | |||
296 | host1x_sync_writel(host, 0x0, HOST1X_SYNC_CFPEEK_CTRL); | ||
297 | } | ||
298 | |||
299 | static void host1x_debug_show_mlocks(struct host1x *host, struct output *o) | ||
300 | { | ||
301 | int i; | ||
302 | |||
303 | host1x_debug_output(o, "---- mlocks ----\n"); | ||
304 | for (i = 0; i < host1x_syncpt_nb_mlocks(host); i++) { | ||
305 | u32 owner = | ||
306 | host1x_sync_readl(host, HOST1X_SYNC_MLOCK_OWNER(i)); | ||
307 | if (HOST1X_SYNC_MLOCK_OWNER_CH_OWNS_V(owner)) | ||
308 | host1x_debug_output(o, "%d: locked by channel %d\n", | ||
309 | i, HOST1X_SYNC_MLOCK_OWNER_CHID_F(owner)); | ||
310 | else if (HOST1X_SYNC_MLOCK_OWNER_CPU_OWNS_V(owner)) | ||
311 | host1x_debug_output(o, "%d: locked by cpu\n", i); | ||
312 | else | ||
313 | host1x_debug_output(o, "%d: unlocked\n", i); | ||
314 | } | ||
315 | host1x_debug_output(o, "\n"); | ||
316 | } | ||
317 | |||
318 | static const struct host1x_debug_ops host1x_debug_ops = { | ||
319 | .show_channel_cdma = host1x_debug_show_channel_cdma, | ||
320 | .show_channel_fifo = host1x_debug_show_channel_fifo, | ||
321 | .show_mlocks = host1x_debug_show_mlocks, | ||
322 | }; | ||
diff --git a/drivers/gpu/host1x/hw/host1x01.c b/drivers/gpu/host1x/hw/host1x01.c index 013ff381d825..a14e91cd1e58 100644 --- a/drivers/gpu/host1x/hw/host1x01.c +++ b/drivers/gpu/host1x/hw/host1x01.c | |||
@@ -23,6 +23,7 @@ | |||
23 | /* include code */ | 23 | /* include code */ |
24 | #include "hw/cdma_hw.c" | 24 | #include "hw/cdma_hw.c" |
25 | #include "hw/channel_hw.c" | 25 | #include "hw/channel_hw.c" |
26 | #include "hw/debug_hw.c" | ||
26 | #include "hw/intr_hw.c" | 27 | #include "hw/intr_hw.c" |
27 | #include "hw/syncpt_hw.c" | 28 | #include "hw/syncpt_hw.c" |
28 | 29 | ||
@@ -35,6 +36,7 @@ int host1x01_init(struct host1x *host) | |||
35 | host->cdma_pb_op = &host1x_pushbuffer_ops; | 36 | host->cdma_pb_op = &host1x_pushbuffer_ops; |
36 | host->syncpt_op = &host1x_syncpt_ops; | 37 | host->syncpt_op = &host1x_syncpt_ops; |
37 | host->intr_op = &host1x_intr_ops; | 38 | host->intr_op = &host1x_intr_ops; |
39 | host->debug_op = &host1x_debug_ops; | ||
38 | 40 | ||
39 | return 0; | 41 | return 0; |
40 | } | 42 | } |
diff --git a/drivers/gpu/host1x/hw/hw_host1x01_channel.h b/drivers/gpu/host1x/hw/hw_host1x01_channel.h index 9ba133205668..b4bc7ca4e051 100644 --- a/drivers/gpu/host1x/hw/hw_host1x01_channel.h +++ b/drivers/gpu/host1x/hw/hw_host1x01_channel.h | |||
@@ -51,6 +51,18 @@ | |||
51 | #ifndef __hw_host1x_channel_host1x_h__ | 51 | #ifndef __hw_host1x_channel_host1x_h__ |
52 | #define __hw_host1x_channel_host1x_h__ | 52 | #define __hw_host1x_channel_host1x_h__ |
53 | 53 | ||
54 | static inline u32 host1x_channel_fifostat_r(void) | ||
55 | { | ||
56 | return 0x0; | ||
57 | } | ||
58 | #define HOST1X_CHANNEL_FIFOSTAT \ | ||
59 | host1x_channel_fifostat_r() | ||
60 | static inline u32 host1x_channel_fifostat_cfempty_v(u32 r) | ||
61 | { | ||
62 | return (r >> 10) & 0x1; | ||
63 | } | ||
64 | #define HOST1X_CHANNEL_FIFOSTAT_CFEMPTY_V(r) \ | ||
65 | host1x_channel_fifostat_cfempty_v(r) | ||
54 | static inline u32 host1x_channel_dmastart_r(void) | 66 | static inline u32 host1x_channel_dmastart_r(void) |
55 | { | 67 | { |
56 | return 0x14; | 68 | return 0x14; |
@@ -87,6 +99,12 @@ static inline u32 host1x_channel_dmactrl_dmastop(void) | |||
87 | } | 99 | } |
88 | #define HOST1X_CHANNEL_DMACTRL_DMASTOP \ | 100 | #define HOST1X_CHANNEL_DMACTRL_DMASTOP \ |
89 | host1x_channel_dmactrl_dmastop() | 101 | host1x_channel_dmactrl_dmastop() |
102 | static inline u32 host1x_channel_dmactrl_dmastop_v(u32 r) | ||
103 | { | ||
104 | return (r >> 0) & 0x1; | ||
105 | } | ||
106 | #define HOST1X_CHANNEL_DMACTRL_DMASTOP_V(r) \ | ||
107 | host1x_channel_dmactrl_dmastop_v(r) | ||
90 | static inline u32 host1x_channel_dmactrl_dmagetrst(void) | 108 | static inline u32 host1x_channel_dmactrl_dmagetrst(void) |
91 | { | 109 | { |
92 | return 1 << 1; | 110 | return 1 << 1; |
diff --git a/drivers/gpu/host1x/hw/hw_host1x01_sync.h b/drivers/gpu/host1x/hw/hw_host1x01_sync.h index 8f2a246c5426..ac704e579977 100644 --- a/drivers/gpu/host1x/hw/hw_host1x01_sync.h +++ b/drivers/gpu/host1x/hw/hw_host1x01_sync.h | |||
@@ -77,6 +77,24 @@ static inline u32 host1x_sync_syncpt_thresh_int_enable_cpu0_r(unsigned int id) | |||
77 | } | 77 | } |
78 | #define HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(id) \ | 78 | #define HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(id) \ |
79 | host1x_sync_syncpt_thresh_int_enable_cpu0_r(id) | 79 | host1x_sync_syncpt_thresh_int_enable_cpu0_r(id) |
80 | static inline u32 host1x_sync_cf_setup_r(unsigned int channel) | ||
81 | { | ||
82 | return 0x80 + channel * REGISTER_STRIDE; | ||
83 | } | ||
84 | #define HOST1X_SYNC_CF_SETUP(channel) \ | ||
85 | host1x_sync_cf_setup_r(channel) | ||
86 | static inline u32 host1x_sync_cf_setup_base_v(u32 r) | ||
87 | { | ||
88 | return (r >> 0) & 0x1ff; | ||
89 | } | ||
90 | #define HOST1X_SYNC_CF_SETUP_BASE_V(r) \ | ||
91 | host1x_sync_cf_setup_base_v(r) | ||
92 | static inline u32 host1x_sync_cf_setup_limit_v(u32 r) | ||
93 | { | ||
94 | return (r >> 16) & 0x1ff; | ||
95 | } | ||
96 | #define HOST1X_SYNC_CF_SETUP_LIMIT_V(r) \ | ||
97 | host1x_sync_cf_setup_limit_v(r) | ||
80 | static inline u32 host1x_sync_cmdproc_stop_r(void) | 98 | static inline u32 host1x_sync_cmdproc_stop_r(void) |
81 | { | 99 | { |
82 | return 0xac; | 100 | return 0xac; |
@@ -107,6 +125,30 @@ static inline u32 host1x_sync_ip_busy_timeout_r(void) | |||
107 | } | 125 | } |
108 | #define HOST1X_SYNC_IP_BUSY_TIMEOUT \ | 126 | #define HOST1X_SYNC_IP_BUSY_TIMEOUT \ |
109 | host1x_sync_ip_busy_timeout_r() | 127 | host1x_sync_ip_busy_timeout_r() |
128 | static inline u32 host1x_sync_mlock_owner_r(unsigned int id) | ||
129 | { | ||
130 | return 0x340 + id * REGISTER_STRIDE; | ||
131 | } | ||
132 | #define HOST1X_SYNC_MLOCK_OWNER(id) \ | ||
133 | host1x_sync_mlock_owner_r(id) | ||
134 | static inline u32 host1x_sync_mlock_owner_chid_f(u32 v) | ||
135 | { | ||
136 | return (v & 0xf) << 8; | ||
137 | } | ||
138 | #define HOST1X_SYNC_MLOCK_OWNER_CHID_F(v) \ | ||
139 | host1x_sync_mlock_owner_chid_f(v) | ||
140 | static inline u32 host1x_sync_mlock_owner_cpu_owns_v(u32 r) | ||
141 | { | ||
142 | return (r >> 1) & 0x1; | ||
143 | } | ||
144 | #define HOST1X_SYNC_MLOCK_OWNER_CPU_OWNS_V(r) \ | ||
145 | host1x_sync_mlock_owner_cpu_owns_v(r) | ||
146 | static inline u32 host1x_sync_mlock_owner_ch_owns_v(u32 r) | ||
147 | { | ||
148 | return (r >> 0) & 0x1; | ||
149 | } | ||
150 | #define HOST1X_SYNC_MLOCK_OWNER_CH_OWNS_V(r) \ | ||
151 | host1x_sync_mlock_owner_ch_owns_v(r) | ||
110 | static inline u32 host1x_sync_syncpt_int_thresh_r(unsigned int id) | 152 | static inline u32 host1x_sync_syncpt_int_thresh_r(unsigned int id) |
111 | { | 153 | { |
112 | return 0x500 + id * REGISTER_STRIDE; | 154 | return 0x500 + id * REGISTER_STRIDE; |
@@ -125,4 +167,77 @@ static inline u32 host1x_sync_syncpt_cpu_incr_r(unsigned int id) | |||
125 | } | 167 | } |
126 | #define HOST1X_SYNC_SYNCPT_CPU_INCR(id) \ | 168 | #define HOST1X_SYNC_SYNCPT_CPU_INCR(id) \ |
127 | host1x_sync_syncpt_cpu_incr_r(id) | 169 | host1x_sync_syncpt_cpu_incr_r(id) |
170 | static inline u32 host1x_sync_cbread_r(unsigned int channel) | ||
171 | { | ||
172 | return 0x720 + channel * REGISTER_STRIDE; | ||
173 | } | ||
174 | #define HOST1X_SYNC_CBREAD(channel) \ | ||
175 | host1x_sync_cbread_r(channel) | ||
176 | static inline u32 host1x_sync_cfpeek_ctrl_r(void) | ||
177 | { | ||
178 | return 0x74c; | ||
179 | } | ||
180 | #define HOST1X_SYNC_CFPEEK_CTRL \ | ||
181 | host1x_sync_cfpeek_ctrl_r() | ||
182 | static inline u32 host1x_sync_cfpeek_ctrl_addr_f(u32 v) | ||
183 | { | ||
184 | return (v & 0x1ff) << 0; | ||
185 | } | ||
186 | #define HOST1X_SYNC_CFPEEK_CTRL_ADDR_F(v) \ | ||
187 | host1x_sync_cfpeek_ctrl_addr_f(v) | ||
188 | static inline u32 host1x_sync_cfpeek_ctrl_channr_f(u32 v) | ||
189 | { | ||
190 | return (v & 0x7) << 16; | ||
191 | } | ||
192 | #define HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(v) \ | ||
193 | host1x_sync_cfpeek_ctrl_channr_f(v) | ||
194 | static inline u32 host1x_sync_cfpeek_ctrl_ena_f(u32 v) | ||
195 | { | ||
196 | return (v & 0x1) << 31; | ||
197 | } | ||
198 | #define HOST1X_SYNC_CFPEEK_CTRL_ENA_F(v) \ | ||
199 | host1x_sync_cfpeek_ctrl_ena_f(v) | ||
200 | static inline u32 host1x_sync_cfpeek_read_r(void) | ||
201 | { | ||
202 | return 0x750; | ||
203 | } | ||
204 | #define HOST1X_SYNC_CFPEEK_READ \ | ||
205 | host1x_sync_cfpeek_read_r() | ||
206 | static inline u32 host1x_sync_cfpeek_ptrs_r(void) | ||
207 | { | ||
208 | return 0x754; | ||
209 | } | ||
210 | #define HOST1X_SYNC_CFPEEK_PTRS \ | ||
211 | host1x_sync_cfpeek_ptrs_r() | ||
212 | static inline u32 host1x_sync_cfpeek_ptrs_cf_rd_ptr_v(u32 r) | ||
213 | { | ||
214 | return (r >> 0) & 0x1ff; | ||
215 | } | ||
216 | #define HOST1X_SYNC_CFPEEK_PTRS_CF_RD_PTR_V(r) \ | ||
217 | host1x_sync_cfpeek_ptrs_cf_rd_ptr_v(r) | ||
218 | static inline u32 host1x_sync_cfpeek_ptrs_cf_wr_ptr_v(u32 r) | ||
219 | { | ||
220 | return (r >> 16) & 0x1ff; | ||
221 | } | ||
222 | #define HOST1X_SYNC_CFPEEK_PTRS_CF_WR_PTR_V(r) \ | ||
223 | host1x_sync_cfpeek_ptrs_cf_wr_ptr_v(r) | ||
224 | static inline u32 host1x_sync_cbstat_r(unsigned int channel) | ||
225 | { | ||
226 | return 0x758 + channel * REGISTER_STRIDE; | ||
227 | } | ||
228 | #define HOST1X_SYNC_CBSTAT(channel) \ | ||
229 | host1x_sync_cbstat_r(channel) | ||
230 | static inline u32 host1x_sync_cbstat_cboffset_v(u32 r) | ||
231 | { | ||
232 | return (r >> 0) & 0xffff; | ||
233 | } | ||
234 | #define HOST1X_SYNC_CBSTAT_CBOFFSET_V(r) \ | ||
235 | host1x_sync_cbstat_cboffset_v(r) | ||
236 | static inline u32 host1x_sync_cbstat_cbclass_v(u32 r) | ||
237 | { | ||
238 | return (r >> 16) & 0x3ff; | ||
239 | } | ||
240 | #define HOST1X_SYNC_CBSTAT_CBCLASS_V(r) \ | ||
241 | host1x_sync_cbstat_cbclass_v(r) | ||
242 | |||
128 | #endif /* __hw_host1x01_sync_h__ */ | 243 | #endif /* __hw_host1x01_sync_h__ */ |
diff --git a/drivers/gpu/host1x/hw/hw_host1x01_uclass.h b/drivers/gpu/host1x/hw/hw_host1x01_uclass.h index 7af660966ad6..42f3ce19ca32 100644 --- a/drivers/gpu/host1x/hw/hw_host1x01_uclass.h +++ b/drivers/gpu/host1x/hw/hw_host1x01_uclass.h | |||
@@ -87,6 +87,12 @@ static inline u32 host1x_uclass_wait_syncpt_thresh_f(u32 v) | |||
87 | } | 87 | } |
88 | #define HOST1X_UCLASS_WAIT_SYNCPT_THRESH_F(v) \ | 88 | #define HOST1X_UCLASS_WAIT_SYNCPT_THRESH_F(v) \ |
89 | host1x_uclass_wait_syncpt_thresh_f(v) | 89 | host1x_uclass_wait_syncpt_thresh_f(v) |
90 | static inline u32 host1x_uclass_wait_syncpt_base_r(void) | ||
91 | { | ||
92 | return 0x9; | ||
93 | } | ||
94 | #define HOST1X_UCLASS_WAIT_SYNCPT_BASE \ | ||
95 | host1x_uclass_wait_syncpt_base_r() | ||
90 | static inline u32 host1x_uclass_wait_syncpt_base_indx_f(u32 v) | 96 | static inline u32 host1x_uclass_wait_syncpt_base_indx_f(u32 v) |
91 | { | 97 | { |
92 | return (v & 0xff) << 24; | 98 | return (v & 0xff) << 24; |
diff --git a/drivers/gpu/host1x/hw/syncpt_hw.c b/drivers/gpu/host1x/hw/syncpt_hw.c index 2c1f4af1094c..61174990102a 100644 --- a/drivers/gpu/host1x/hw/syncpt_hw.c +++ b/drivers/gpu/host1x/hw/syncpt_hw.c | |||
@@ -86,6 +86,7 @@ static void syncpt_cpu_incr(struct host1x_syncpt *sp) | |||
86 | host1x_syncpt_idle(sp)) { | 86 | host1x_syncpt_idle(sp)) { |
87 | dev_err(host->dev, "Trying to increment syncpoint id %d beyond max\n", | 87 | dev_err(host->dev, "Trying to increment syncpoint id %d beyond max\n", |
88 | sp->id); | 88 | sp->id); |
89 | host1x_debug_dump(sp->host); | ||
89 | return; | 90 | return; |
90 | } | 91 | } |
91 | host1x_sync_writel(host, BIT_MASK(sp->id), | 92 | host1x_sync_writel(host, BIT_MASK(sp->id), |
diff --git a/drivers/gpu/host1x/syncpt.c b/drivers/gpu/host1x/syncpt.c index 7e77e63da57b..4b493453e805 100644 --- a/drivers/gpu/host1x/syncpt.c +++ b/drivers/gpu/host1x/syncpt.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include "syncpt.h" | 25 | #include "syncpt.h" |
26 | #include "dev.h" | 26 | #include "dev.h" |
27 | #include "intr.h" | 27 | #include "intr.h" |
28 | #include "debug.h" | ||
28 | 29 | ||
29 | #define SYNCPT_CHECK_PERIOD (2 * HZ) | 30 | #define SYNCPT_CHECK_PERIOD (2 * HZ) |
30 | #define MAX_STUCK_CHECK_COUNT 15 | 31 | #define MAX_STUCK_CHECK_COUNT 15 |
@@ -231,6 +232,10 @@ int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout, | |||
231 | "%s: syncpoint id %d (%s) stuck waiting %d, timeout=%ld\n", | 232 | "%s: syncpoint id %d (%s) stuck waiting %d, timeout=%ld\n", |
232 | current->comm, sp->id, sp->name, | 233 | current->comm, sp->id, sp->name, |
233 | thresh, timeout); | 234 | thresh, timeout); |
235 | |||
236 | host1x_debug_dump_syncpts(sp->host); | ||
237 | if (check_count == MAX_STUCK_CHECK_COUNT) | ||
238 | host1x_debug_dump(sp->host); | ||
234 | check_count++; | 239 | check_count++; |
235 | } | 240 | } |
236 | } | 241 | } |