Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/gpu/host1x/debug.c
26428 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Copyright (C) 2010 Google, Inc.
4
* Author: Erik Gilling <[email protected]>
5
*
6
* Copyright (C) 2011-2013 NVIDIA Corporation
7
*/
8
9
#include <linux/debugfs.h>
10
#include <linux/pm_runtime.h>
11
#include <linux/seq_file.h>
12
#include <linux/uaccess.h>
13
14
#include <linux/io.h>
15
16
#include "dev.h"
17
#include "debug.h"
18
#include "channel.h"
19
20
static DEFINE_MUTEX(debug_lock);
21
22
unsigned int host1x_debug_trace_cmdbuf;
23
24
static pid_t host1x_debug_force_timeout_pid;
25
static u32 host1x_debug_force_timeout_val;
26
static u32 host1x_debug_force_timeout_channel;
27
28
void host1x_debug_output(struct output *o, const char *fmt, ...)
29
{
30
va_list args;
31
int len;
32
33
va_start(args, fmt);
34
len = vsnprintf(o->buf, sizeof(o->buf), fmt, args);
35
va_end(args);
36
37
o->fn(o->ctx, o->buf, len, false);
38
}
39
40
void host1x_debug_cont(struct output *o, const char *fmt, ...)
41
{
42
va_list args;
43
int len;
44
45
va_start(args, fmt);
46
len = vsnprintf(o->buf, sizeof(o->buf), fmt, args);
47
va_end(args);
48
49
o->fn(o->ctx, o->buf, len, true);
50
}
51
52
static int show_channel(struct host1x_channel *ch, void *data, bool show_fifo)
53
{
54
struct host1x *m = dev_get_drvdata(ch->dev->parent);
55
struct output *o = data;
56
int err;
57
58
err = pm_runtime_resume_and_get(m->dev);
59
if (err < 0)
60
return err;
61
62
mutex_lock(&ch->cdma.lock);
63
mutex_lock(&debug_lock);
64
65
if (show_fifo)
66
host1x_hw_show_channel_fifo(m, ch, o);
67
68
host1x_hw_show_channel_cdma(m, ch, o);
69
70
mutex_unlock(&debug_lock);
71
mutex_unlock(&ch->cdma.lock);
72
73
pm_runtime_put(m->dev);
74
75
return 0;
76
}
77
78
static void show_syncpts(struct host1x *m, struct output *o, bool show_all)
79
{
80
unsigned long irqflags;
81
struct list_head *pos;
82
unsigned int i;
83
int err;
84
85
host1x_debug_output(o, "---- syncpts ----\n");
86
87
err = pm_runtime_resume_and_get(m->dev);
88
if (err < 0)
89
return;
90
91
for (i = 0; i < host1x_syncpt_nb_pts(m); i++) {
92
u32 max = host1x_syncpt_read_max(m->syncpt + i);
93
u32 min = host1x_syncpt_load(m->syncpt + i);
94
unsigned int waiters = 0;
95
96
spin_lock_irqsave(&m->syncpt[i].fences.lock, irqflags);
97
list_for_each(pos, &m->syncpt[i].fences.list)
98
waiters++;
99
spin_unlock_irqrestore(&m->syncpt[i].fences.lock, irqflags);
100
101
if (!kref_read(&m->syncpt[i].ref))
102
continue;
103
104
if (!show_all && !min && !max && !waiters)
105
continue;
106
107
host1x_debug_output(o,
108
"id %u (%s) min %d max %d (%d waiters)\n",
109
i, m->syncpt[i].name, min, max, waiters);
110
}
111
112
for (i = 0; i < host1x_syncpt_nb_bases(m); i++) {
113
u32 base_val;
114
115
base_val = host1x_syncpt_load_wait_base(m->syncpt + i);
116
if (base_val)
117
host1x_debug_output(o, "waitbase id %u val %d\n", i,
118
base_val);
119
}
120
121
pm_runtime_put(m->dev);
122
123
host1x_debug_output(o, "\n");
124
}
125
126
static void show_all(struct host1x *m, struct output *o, bool show_fifo)
127
{
128
unsigned int i;
129
130
host1x_hw_show_mlocks(m, o);
131
show_syncpts(m, o, true);
132
host1x_debug_output(o, "---- channels ----\n");
133
134
for (i = 0; i < m->info->nb_channels; ++i) {
135
struct host1x_channel *ch = host1x_channel_get_index(m, i);
136
137
if (ch) {
138
show_channel(ch, o, show_fifo);
139
host1x_channel_put(ch);
140
}
141
}
142
}
143
144
static int host1x_debug_all_show(struct seq_file *s, void *unused)
145
{
146
struct output o = {
147
.fn = write_to_seqfile,
148
.ctx = s
149
};
150
151
show_all(s->private, &o, true);
152
153
return 0;
154
}
155
DEFINE_SHOW_ATTRIBUTE(host1x_debug_all);
156
157
static int host1x_debug_show(struct seq_file *s, void *unused)
158
{
159
struct output o = {
160
.fn = write_to_seqfile,
161
.ctx = s
162
};
163
164
show_all(s->private, &o, false);
165
166
return 0;
167
}
168
DEFINE_SHOW_ATTRIBUTE(host1x_debug);
169
170
static void host1x_debugfs_init(struct host1x *host1x)
171
{
172
struct dentry *de = debugfs_create_dir("tegra-host1x", NULL);
173
174
/* Store the created entry */
175
host1x->debugfs = de;
176
177
debugfs_create_file("status", S_IRUGO, de, host1x, &host1x_debug_fops);
178
debugfs_create_file("status_all", S_IRUGO, de, host1x,
179
&host1x_debug_all_fops);
180
181
debugfs_create_u32("trace_cmdbuf", S_IRUGO|S_IWUSR, de,
182
&host1x_debug_trace_cmdbuf);
183
184
host1x_hw_debug_init(host1x, de);
185
186
debugfs_create_u32("force_timeout_pid", S_IRUGO|S_IWUSR, de,
187
&host1x_debug_force_timeout_pid);
188
debugfs_create_u32("force_timeout_val", S_IRUGO|S_IWUSR, de,
189
&host1x_debug_force_timeout_val);
190
debugfs_create_u32("force_timeout_channel", S_IRUGO|S_IWUSR, de,
191
&host1x_debug_force_timeout_channel);
192
}
193
194
static void host1x_debugfs_exit(struct host1x *host1x)
195
{
196
debugfs_remove_recursive(host1x->debugfs);
197
}
198
199
void host1x_debug_init(struct host1x *host1x)
200
{
201
if (IS_ENABLED(CONFIG_DEBUG_FS))
202
host1x_debugfs_init(host1x);
203
}
204
205
void host1x_debug_deinit(struct host1x *host1x)
206
{
207
if (IS_ENABLED(CONFIG_DEBUG_FS))
208
host1x_debugfs_exit(host1x);
209
}
210
211
void host1x_debug_dump(struct host1x *host1x)
212
{
213
struct output o = {
214
.fn = write_to_printk
215
};
216
217
show_all(host1x, &o, true);
218
}
219
220