aboutsummaryrefslogtreecommitdiffstats
path: root/include/os/linux/ioctl_dbg.c
diff options
context:
space:
mode:
Diffstat (limited to 'include/os/linux/ioctl_dbg.c')
-rw-r--r--include/os/linux/ioctl_dbg.c2210
1 files changed, 2210 insertions, 0 deletions
diff --git a/include/os/linux/ioctl_dbg.c b/include/os/linux/ioctl_dbg.c
new file mode 100644
index 0000000..b5a1071
--- /dev/null
+++ b/include/os/linux/ioctl_dbg.c
@@ -0,0 +1,2210 @@
1/*
2 * Tegra GK20A GPU Debugger/Profiler Driver
3 *
4 * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
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
19#include <linux/fs.h>
20#include <linux/file.h>
21#include <linux/cdev.h>
22#include <linux/uaccess.h>
23#include <linux/dma-buf.h>
24#include <linux/poll.h>
25#include <uapi/linux/nvgpu.h>
26
27#include <nvgpu/kmem.h>
28#include <nvgpu/log.h>
29#include <nvgpu/vm.h>
30#include <nvgpu/atomic.h>
31#include <nvgpu/cond.h>
32#include <nvgpu/utils.h>
33#include <nvgpu/gk20a.h>
34#include <nvgpu/channel.h>
35#include <nvgpu/tsg.h>
36
37#include <nvgpu/linux/vm.h>
38
39#include "gk20a/gr_gk20a.h"
40#include "gk20a/regops_gk20a.h"
41#include "gk20a/dbg_gpu_gk20a.h"
42#include "os_linux.h"
43#include "platform_gk20a.h"
44#include "ioctl_dbg.h"
45#include "ioctl_channel.h"
46#include "dmabuf_vidmem.h"
47
48struct dbg_session_gk20a_linux {
49 struct device *dev;
50 struct dbg_session_gk20a dbg_s;
51};
52
53struct dbg_session_channel_data_linux {
54 /*
55 * We have to keep a ref to the _file_, not the channel, because
56 * close(channel_fd) is synchronous and would deadlock if we had an
57 * open debug session fd holding a channel ref at that time. Holding a
58 * ref to the file makes close(channel_fd) just drop a kernel ref to
59 * the file; the channel will close when the last file ref is dropped.
60 */
61 struct file *ch_f;
62 struct dbg_session_channel_data ch_data;
63};
64/* turn seriously unwieldy names -> something shorter */
65#define REGOP_LINUX(x) NVGPU_DBG_GPU_REG_OP_##x
66
67/* silly allocator - just increment id */
68static nvgpu_atomic_t unique_id = NVGPU_ATOMIC_INIT(0);
69static int generate_unique_id(void)
70{
71 return nvgpu_atomic_add_return(1, &unique_id);
72}
73
74static int alloc_profiler(struct gk20a *g,
75 struct dbg_profiler_object_data **_prof)
76{
77 struct dbg_profiler_object_data *prof;
78 *_prof = NULL;
79
80 nvgpu_log(g, gpu_dbg_fn | gpu_dbg_gpu_dbg, " ");
81
82 prof = nvgpu_kzalloc(g, sizeof(*prof));
83 if (!prof)
84 return -ENOMEM;
85
86 prof->prof_handle = generate_unique_id();
87 *_prof = prof;
88 return 0;
89}
90
91static int alloc_session(struct gk20a *g, struct dbg_session_gk20a_linux **_dbg_s_linux)
92{
93 struct dbg_session_gk20a_linux *dbg_s_linux;
94 *_dbg_s_linux = NULL;
95
96 nvgpu_log(g, gpu_dbg_fn | gpu_dbg_gpu_dbg, " ");
97
98 dbg_s_linux = nvgpu_kzalloc(g, sizeof(*dbg_s_linux));
99 if (!dbg_s_linux)
100 return -ENOMEM;
101
102 dbg_s_linux->dbg_s.id = generate_unique_id();
103 *_dbg_s_linux = dbg_s_linux;
104 return 0;
105}
106
107static int gk20a_perfbuf_release_locked(struct gk20a *g, u64 offset);
108
109static int nvgpu_ioctl_channel_reg_ops(struct dbg_session_gk20a *dbg_s,
110 struct nvgpu_dbg_gpu_exec_reg_ops_args *args);
111
112static int nvgpu_ioctl_powergate_gk20a(struct dbg_session_gk20a *dbg_s,
113 struct nvgpu_dbg_gpu_powergate_args *args);
114
115static int nvgpu_dbg_gpu_ioctl_smpc_ctxsw_mode(struct dbg_session_gk20a *dbg_s,
116 struct nvgpu_dbg_gpu_smpc_ctxsw_mode_args *args);
117
118static int nvgpu_dbg_gpu_ioctl_hwpm_ctxsw_mode(struct dbg_session_gk20a *dbg_s,
119 struct nvgpu_dbg_gpu_hwpm_ctxsw_mode_args *args);
120
121static int nvgpu_dbg_gpu_ioctl_set_mmu_debug_mode(
122 struct dbg_session_gk20a *dbg_s,
123 struct nvgpu_dbg_gpu_set_ctx_mmu_debug_mode_args *args);
124
125static int nvgpu_dbg_gpu_ioctl_suspend_resume_sm(
126 struct dbg_session_gk20a *dbg_s,
127 struct nvgpu_dbg_gpu_suspend_resume_all_sms_args *args);
128
129static int nvgpu_ioctl_allocate_profiler_object(struct dbg_session_gk20a_linux *dbg_s,
130 struct nvgpu_dbg_gpu_profiler_obj_mgt_args *args);
131
132static int nvgpu_ioctl_free_profiler_object(struct dbg_session_gk20a_linux *dbg_s_linux,
133 struct nvgpu_dbg_gpu_profiler_obj_mgt_args *args);
134
135static int nvgpu_ioctl_profiler_reserve(struct dbg_session_gk20a *dbg_s,
136 struct nvgpu_dbg_gpu_profiler_reserve_args *args);
137
138static int gk20a_perfbuf_map(struct dbg_session_gk20a *dbg_s,
139 struct nvgpu_dbg_gpu_perfbuf_map_args *args);
140
141static int gk20a_perfbuf_unmap(struct dbg_session_gk20a *dbg_s,
142 struct nvgpu_dbg_gpu_perfbuf_unmap_args *args);
143
144static int nvgpu_dbg_timeout_enable(struct dbg_session_gk20a *dbg_s,
145 int timeout_mode);
146
147static int nvgpu_profiler_reserve_acquire(struct dbg_session_gk20a *dbg_s,
148 u32 profiler_handle);
149
150static void gk20a_dbg_session_nvgpu_mutex_acquire(struct dbg_session_gk20a *dbg_s);
151
152static void gk20a_dbg_session_nvgpu_mutex_release(struct dbg_session_gk20a *dbg_s);
153
154static int nvgpu_profiler_reserve_release(struct dbg_session_gk20a *dbg_s,
155 u32 profiler_handle);
156
157static int dbg_unbind_all_channels_gk20a(struct dbg_session_gk20a *dbg_s);
158
159static int gk20a_dbg_gpu_do_dev_open(struct inode *inode,
160 struct file *filp, bool is_profiler);
161
162static int nvgpu_set_sm_exception_type_mask_locked(
163 struct dbg_session_gk20a *dbg_s,
164 u32 exception_mask);
165
166unsigned int gk20a_dbg_gpu_dev_poll(struct file *filep, poll_table *wait)
167{
168 unsigned int mask = 0;
169 struct dbg_session_gk20a_linux *dbg_session_linux = filep->private_data;
170 struct dbg_session_gk20a *dbg_s = &dbg_session_linux->dbg_s;
171 struct gk20a *g = dbg_s->g;
172
173 nvgpu_log(g, gpu_dbg_fn | gpu_dbg_gpu_dbg, " ");
174
175 poll_wait(filep, &dbg_s->dbg_events.wait_queue.wq, wait);
176
177 gk20a_dbg_session_nvgpu_mutex_acquire(dbg_s);
178
179 if (dbg_s->dbg_events.events_enabled &&
180 dbg_s->dbg_events.num_pending_events > 0) {
181 nvgpu_log(g, gpu_dbg_gpu_dbg, "found pending event on session id %d",
182 dbg_s->id);
183 nvgpu_log(g, gpu_dbg_gpu_dbg, "%d events pending",
184 dbg_s->dbg_events.num_pending_events);
185 mask = (POLLPRI | POLLIN);
186 }
187
188 gk20a_dbg_session_nvgpu_mutex_release(dbg_s);
189
190 return mask;
191}
192
193int gk20a_dbg_gpu_dev_release(struct inode *inode, struct file *filp)
194{
195 struct dbg_session_gk20a_linux *dbg_session_linux = filp->private_data;
196 struct dbg_session_gk20a *dbg_s = &dbg_session_linux->dbg_s;
197 struct gk20a *g = dbg_s->g;
198 struct dbg_profiler_object_data *prof_obj, *tmp_obj;
199
200 nvgpu_log(g, gpu_dbg_gpu_dbg | gpu_dbg_fn, "%s", g->name);
201
202 /* unbind channels */
203 dbg_unbind_all_channels_gk20a(dbg_s);
204
205 /* Powergate/Timeout enable is called here as possibility of dbg_session
206 * which called powergate/timeout disable ioctl, to be killed without
207 * calling powergate/timeout enable ioctl
208 */
209 nvgpu_mutex_acquire(&g->dbg_sessions_lock);
210 if (dbg_s->is_pg_disabled) {
211 nvgpu_set_powergate_locked(dbg_s, false);
212 }
213 nvgpu_dbg_timeout_enable(dbg_s, NVGPU_DBG_GPU_IOCTL_TIMEOUT_ENABLE);
214
215 /* If this session owned the perf buffer, release it */
216 if (g->perfbuf.owner == dbg_s)
217 gk20a_perfbuf_release_locked(g, g->perfbuf.offset);
218