summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/os/linux/debug_fecs_trace.c
blob: 7786053f7b89b54f782cabdeda49379c717378cc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/*
 * Copyright (c) 2018-2020, NVIDIA CORPORATION. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <linux/debugfs.h>

#include <nvgpu/fecs_trace.h>

#include "os_linux.h"

/*
 * The sequence iterator functions.  We simply use the count of the
 * next line as our internal position.
 */
static void *gk20a_fecs_trace_debugfs_ring_seq_start(
		struct seq_file *s, loff_t *pos)
{
	if (*pos >= GK20A_FECS_TRACE_NUM_RECORDS)
		return NULL;

	return pos;
}

static void *gk20a_fecs_trace_debugfs_ring_seq_next(
		struct seq_file *s, void *v, loff_t *pos)
{
	++(*pos);
	if (*pos >= GK20A_FECS_TRACE_NUM_RECORDS)
		return NULL;
	return pos;
}

static void gk20a_fecs_trace_debugfs_ring_seq_stop(
		struct seq_file *s, void *v)
{
}

static int gk20a_fecs_trace_debugfs_ring_seq_show(
		struct seq_file *s, void *v)
{
	loff_t *pos = (loff_t *) v;
	struct gk20a *g = *(struct gk20a **)s->private;
	struct gk20a_fecs_trace_record *r =
		gk20a_fecs_trace_get_record(g, *pos);
	int i;
	const u32 invalid_tag = gk20a_fecs_trace_record_ts_tag_invalid_ts_v();
	u32 tag;
	u64 timestamp;

	seq_printf(s, "record #%lld (%p)\n", *pos, r);
	seq_printf(s, "\tmagic_lo=%08x\n", r->magic_lo);
	seq_printf(s, "\tmagic_hi=%08x\n", r->magic_hi);
	if (gk20a_fecs_trace_is_valid_record(r)) {
		seq_printf(s, "\tcontext_ptr=%08x\n", r->context_ptr);
		seq_printf(s, "\tcontext_id=%08x\n", r->context_id);
		seq_printf(s, "\tnew_context_ptr=%08x\n", r->new_context_ptr);
		seq_printf(s, "\tnew_context_id=%08x\n", r->new_context_id);
		for (i = 0; i < gk20a_fecs_trace_num_ts(); i++) {
			tag = gk20a_fecs_trace_record_ts_tag_v(r->ts[i]);
			if (tag == invalid_tag)
				continue;
			timestamp = gk20a_fecs_trace_record_ts_timestamp_v(r->ts[i]);
			timestamp <<= GK20A_FECS_TRACE_PTIMER_SHIFT;
			seq_printf(s, "\ttag=%02x timestamp=%012llx\n", tag, timestamp);
		}
	}
	return 0;
}

/*
 * Tie them all together into a set of seq_operations.
 */
static const struct seq_operations gk20a_fecs_trace_debugfs_ring_seq_ops = {
	.start = gk20a_fecs_trace_debugfs_ring_seq_start,
	.next = gk20a_fecs_trace_debugfs_ring_seq_next,
	.stop = gk20a_fecs_trace_debugfs_ring_seq_stop,
	.show = gk20a_fecs_trace_debugfs_ring_seq_show
};

/*
 * Time to set up the file operations for our /proc file.  In this case,
 * all we need is an open function which sets up the sequence ops.
 */

static int gk20a_ctxsw_debugfs_ring_open(struct inode *inode,
	struct file *file)
{
	struct gk20a **p;

	p = __seq_open_private(file, &gk20a_fecs_trace_debugfs_ring_seq_ops,
		sizeof(struct gk20a *));
	if (!p)
		return -ENOMEM;

	*p = (struct gk20a *)inode->i_private;
	return 0;
};

/*
 * The file operations structure contains our open function along with
 * set of the canned seq_ ops.
 */
static const struct file_operations gk20a_fecs_trace_debugfs_ring_fops = {
	.owner = THIS_MODULE,
	.open = gk20a_ctxsw_debugfs_ring_open,
	.read = seq_read,
	.llseek = seq_lseek,
	.release = seq_release_private
};

static int gk20a_fecs_trace_debugfs_read(void *arg, u64 *val)
{
	*val = gk20a_fecs_trace_get_read_index((struct gk20a *)arg);
	return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(gk20a_fecs_trace_debugfs_read_fops,
	gk20a_fecs_trace_debugfs_read, NULL, "%llu\n");

static int gk20a_fecs_trace_debugfs_write(void *arg, u64 *val)
{
	*val = gk20a_fecs_trace_get_write_index((struct gk20a *)arg);
	return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(gk20a_fecs_trace_debugfs_write_fops,
	gk20a_fecs_trace_debugfs_write, NULL, "%llu\n");

int nvgpu_fecs_trace_init_debugfs(struct gk20a *g)
{
	struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);

	debugfs_create_file("ctxsw_trace_read", 0600, l->debugfs, g,
		&gk20a_fecs_trace_debugfs_read_fops);
	debugfs_create_file("ctxsw_trace_write", 0600, l->debugfs, g,
		&gk20a_fecs_trace_debugfs_write_fops);
	debugfs_create_file("ctxsw_trace_ring", 0600, l->debugfs, g,
		&gk20a_fecs_trace_debugfs_ring_fops);

	return 0;
}