Commit 6236451d83a720072053855fa63d51934024a707
Committed by
Thierry Reding
1 parent
6579324a41
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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>
Showing 15 changed files with 807 additions and 0 deletions Side-by-side Diff
- drivers/gpu/host1x/Makefile
- drivers/gpu/host1x/cdma.c
- drivers/gpu/host1x/debug.c
- drivers/gpu/host1x/debug.h
- drivers/gpu/host1x/dev.c
- drivers/gpu/host1x/dev.h
- drivers/gpu/host1x/hw/cdma_hw.c
- drivers/gpu/host1x/hw/channel_hw.c
- drivers/gpu/host1x/hw/debug_hw.c
- drivers/gpu/host1x/hw/host1x01.c
- drivers/gpu/host1x/hw/hw_host1x01_channel.h
- drivers/gpu/host1x/hw/hw_host1x01_sync.h
- drivers/gpu/host1x/hw/hw_host1x01_uclass.h
- drivers/gpu/host1x/hw/syncpt_hw.c
- drivers/gpu/host1x/syncpt.c
drivers/gpu/host1x/Makefile
drivers/gpu/host1x/cdma.c
... | ... | @@ -439,6 +439,10 @@ |
439 | 439 | struct push_buffer *pb = &cdma->push_buffer; |
440 | 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 | 446 | if (slots_free == 0) { |
443 | 447 | host1x_hw_cdma_flush(host1x, cdma); |
444 | 448 | slots_free = host1x_cdma_wait_locked(cdma, |
drivers/gpu/host1x/debug.c
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 | +} |
drivers/gpu/host1x/debug.h
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 |
drivers/gpu/host1x/dev.c
... | ... | @@ -30,6 +30,7 @@ |
30 | 30 | #include "dev.h" |
31 | 31 | #include "intr.h" |
32 | 32 | #include "channel.h" |
33 | +#include "debug.h" | |
33 | 34 | #include "hw/host1x01.h" |
34 | 35 | |
35 | 36 | void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r) |
... | ... | @@ -146,6 +147,8 @@ |
146 | 147 | dev_err(&pdev->dev, "failed to initialize interrupts\n"); |
147 | 148 | goto fail_deinit_syncpt; |
148 | 149 | } |
150 | + | |
151 | + host1x_debug_init(host); | |
149 | 152 | |
150 | 153 | return 0; |
151 | 154 |
drivers/gpu/host1x/dev.h
... | ... | @@ -31,6 +31,8 @@ |
31 | 31 | struct host1x_cdma; |
32 | 32 | struct host1x_job; |
33 | 33 | struct push_buffer; |
34 | +struct output; | |
35 | +struct dentry; | |
34 | 36 | |
35 | 37 | struct host1x_channel_ops { |
36 | 38 | int (*init)(struct host1x_channel *channel, struct host1x *host, |
... | ... | @@ -54,6 +56,18 @@ |
54 | 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 | 71 | struct host1x_syncpt_ops { |
58 | 72 | void (*restore)(struct host1x_syncpt *syncpt); |
59 | 73 | void (*restore_wait_base)(struct host1x_syncpt *syncpt); |
... | ... | @@ -100,6 +114,7 @@ |
100 | 114 | const struct host1x_channel_ops *channel_op; |
101 | 115 | const struct host1x_cdma_ops *cdma_op; |
102 | 116 | const struct host1x_pushbuffer_ops *cdma_pb_op; |
117 | + const struct host1x_debug_ops *debug_op; | |
103 | 118 | |
104 | 119 | struct host1x_syncpt *nop_sp; |
105 | 120 | |
... | ... | @@ -107,6 +122,8 @@ |
107 | 122 | struct host1x_channel chlist; |
108 | 123 | unsigned long allocated_channels; |
109 | 124 | unsigned int num_allocated_channels; |
125 | + | |
126 | + struct dentry *debugfs; | |
110 | 127 | }; |
111 | 128 | |
112 | 129 | void host1x_sync_writel(struct host1x *host1x, u32 r, u32 v); |
... | ... | @@ -255,6 +272,31 @@ |
255 | 272 | struct push_buffer *pb) |
256 | 273 | { |
257 | 274 | host->cdma_pb_op->init(pb); |
275 | +} | |
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); | |
258 | 300 | } |
259 | 301 | |
260 | 302 | #endif |
drivers/gpu/host1x/hw/cdma_hw.c
drivers/gpu/host1x/hw/channel_hw.c
... | ... | @@ -29,6 +29,30 @@ |
29 | 29 | #define HOST1X_CHANNEL_SIZE 16384 |
30 | 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 | 56 | static void submit_gathers(struct host1x_job *job) |
33 | 57 | { |
34 | 58 | struct host1x_cdma *cdma = &job->channel->cdma; |
... | ... | @@ -38,6 +62,7 @@ |
38 | 62 | struct host1x_job_gather *g = &job->gathers[i]; |
39 | 63 | u32 op1 = host1x_opcode_gather(g->words); |
40 | 64 | u32 op2 = g->base + g->offset; |
65 | + trace_write_gather(cdma, g->bo, g->offset, op1 & 0xffff); | |
41 | 66 | host1x_cdma_push(cdma, op1, op2); |
42 | 67 | } |
43 | 68 | } |
drivers/gpu/host1x/hw/debug_hw.c
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 | +}; |
drivers/gpu/host1x/hw/host1x01.c
... | ... | @@ -23,6 +23,7 @@ |
23 | 23 | /* include code */ |
24 | 24 | #include "hw/cdma_hw.c" |
25 | 25 | #include "hw/channel_hw.c" |
26 | +#include "hw/debug_hw.c" | |
26 | 27 | #include "hw/intr_hw.c" |
27 | 28 | #include "hw/syncpt_hw.c" |
28 | 29 | |
... | ... | @@ -35,6 +36,7 @@ |
35 | 36 | host->cdma_pb_op = &host1x_pushbuffer_ops; |
36 | 37 | host->syncpt_op = &host1x_syncpt_ops; |
37 | 38 | host->intr_op = &host1x_intr_ops; |
39 | + host->debug_op = &host1x_debug_ops; | |
38 | 40 | |
39 | 41 | return 0; |
40 | 42 | } |
drivers/gpu/host1x/hw/hw_host1x01_channel.h
... | ... | @@ -51,6 +51,18 @@ |
51 | 51 | #ifndef __hw_host1x_channel_host1x_h__ |
52 | 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 | 66 | static inline u32 host1x_channel_dmastart_r(void) |
55 | 67 | { |
56 | 68 | return 0x14; |
... | ... | @@ -87,6 +99,12 @@ |
87 | 99 | } |
88 | 100 | #define HOST1X_CHANNEL_DMACTRL_DMASTOP \ |
89 | 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 | 108 | static inline u32 host1x_channel_dmactrl_dmagetrst(void) |
91 | 109 | { |
92 | 110 | return 1 << 1; |
drivers/gpu/host1x/hw/hw_host1x01_sync.h
... | ... | @@ -77,6 +77,24 @@ |
77 | 77 | } |
78 | 78 | #define HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(id) \ |
79 | 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 | 98 | static inline u32 host1x_sync_cmdproc_stop_r(void) |
81 | 99 | { |
82 | 100 | return 0xac; |
... | ... | @@ -107,6 +125,30 @@ |
107 | 125 | } |
108 | 126 | #define HOST1X_SYNC_IP_BUSY_TIMEOUT \ |
109 | 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 | 152 | static inline u32 host1x_sync_syncpt_int_thresh_r(unsigned int id) |
111 | 153 | { |
112 | 154 | return 0x500 + id * REGISTER_STRIDE; |
... | ... | @@ -125,5 +167,78 @@ |
125 | 167 | } |
126 | 168 | #define HOST1X_SYNC_SYNCPT_CPU_INCR(id) \ |
127 | 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 | 243 | #endif /* __hw_host1x01_sync_h__ */ |
drivers/gpu/host1x/hw/hw_host1x01_uclass.h
... | ... | @@ -87,6 +87,12 @@ |
87 | 87 | } |
88 | 88 | #define HOST1X_UCLASS_WAIT_SYNCPT_THRESH_F(v) \ |
89 | 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 | 96 | static inline u32 host1x_uclass_wait_syncpt_base_indx_f(u32 v) |
91 | 97 | { |
92 | 98 | return (v & 0xff) << 24; |
drivers/gpu/host1x/hw/syncpt_hw.c
drivers/gpu/host1x/syncpt.c
... | ... | @@ -25,6 +25,7 @@ |
25 | 25 | #include "syncpt.h" |
26 | 26 | #include "dev.h" |
27 | 27 | #include "intr.h" |
28 | +#include "debug.h" | |
28 | 29 | |
29 | 30 | #define SYNCPT_CHECK_PERIOD (2 * HZ) |
30 | 31 | #define MAX_STUCK_CHECK_COUNT 15 |
... | ... | @@ -231,6 +232,10 @@ |
231 | 232 | "%s: syncpoint id %d (%s) stuck waiting %d, timeout=%ld\n", |
232 | 233 | current->comm, sp->id, sp->name, |
233 | 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 | 239 | check_count++; |
235 | 240 | } |
236 | 241 | } |