summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c')
-rw-r--r--drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c367
1 files changed, 367 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c b/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c
new file mode 100644
index 00000000..cf04e116
--- /dev/null
+++ b/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c
@@ -0,0 +1,367 @@
1/*
2 * Tegra GK20A GPU Debugger/Profiler Driver
3 *
4 * Copyright (c) 2013-2017, NVIDIA CORPORATION. All rights reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
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/mm.h>
32
33#include "gk20a.h"
34#include "gr_gk20a.h"
35#include "dbg_gpu_gk20a.h"
36#include "regops_gk20a.h"
37
38#include <nvgpu/hw/gk20a/hw_therm_gk20a.h>
39#include <nvgpu/hw/gk20a/hw_gr_gk20a.h>
40#include <nvgpu/hw/gk20a/hw_perf_gk20a.h>
41
42/*
43 * API to get first channel from the list of all channels
44 * bound to the debug session
45 */
46struct channel_gk20a *
47nvgpu_dbg_gpu_get_session_channel(struct dbg_session_gk20a *dbg_s)
48{
49 struct dbg_session_channel_data *ch_data;
50 struct channel_gk20a *ch;
51 struct gk20a *g = dbg_s->g;
52
53 nvgpu_mutex_acquire(&dbg_s->ch_list_lock);
54 if (nvgpu_list_empty(&dbg_s->ch_list)) {
55 nvgpu_mutex_release(&dbg_s->ch_list_lock);
56 return NULL;
57 }
58
59 ch_data = nvgpu_list_first_entry(&dbg_s->ch_list,
60 dbg_session_channel_data,
61 ch_entry);
62 ch = g->fifo.channel + ch_data->chid;
63
64 nvgpu_mutex_release(&dbg_s->ch_list_lock);
65
66 return ch;
67}
68
69void gk20a_dbg_gpu_post_events(struct channel_gk20a *ch)
70{
71 struct dbg_session_data *session_data;
72 struct dbg_session_gk20a *dbg_s;
73
74 gk20a_dbg(gpu_dbg_fn | gpu_dbg_gpu_dbg, "");
75
76 /* guard against the session list being modified */
77 nvgpu_mutex_acquire(&ch->dbg_s_lock);
78
79 nvgpu_list_for_each_entry(session_data, &ch->dbg_s_list,
80 dbg_session_data, dbg_s_entry) {
81 dbg_s = session_data->dbg_s;
82 if (dbg_s->dbg_events.events_enabled) {
83 gk20a_dbg(gpu_dbg_gpu_dbg, "posting event on session id %d",
84 dbg_s->id);
85 gk20a_dbg(gpu_dbg_gpu_dbg, "%d events pending",
86 dbg_s->dbg_events.num_pending_events);
87
88 dbg_s->dbg_events.num_pending_events++;
89
90 nvgpu_cond_broadcast_interruptible(&dbg_s->dbg_events.wait_queue);
91 }
92 }
93
94 nvgpu_mutex_release(&ch->dbg_s_lock);
95}
96
97bool gk20a_dbg_gpu_broadcast_stop_trigger(struct channel_gk20a *ch)
98{
99 struct dbg_session_data *session_data;
100 struct dbg_session_gk20a *dbg_s;
101 bool broadcast = false;
102
103 gk20a_dbg(gpu_dbg_fn | gpu_dbg_gpu_dbg | gpu_dbg_intr, "");
104
105 /* guard against the session list being modified */
106 nvgpu_mutex_acquire(&ch->dbg_s_lock);
107
108 nvgpu_list_for_each_entry(session_data, &ch->dbg_s_list,
109 dbg_session_data, dbg_s_entry) {
110 dbg_s = session_data->dbg_s;
111 if (dbg_s->broadcast_stop_trigger) {
112 gk20a_dbg(gpu_dbg_gpu_dbg | gpu_dbg_fn | gpu_dbg_intr,
113 "stop trigger broadcast enabled");
114 broadcast = true;
115 break;
116 }
117 }
118
119 nvgpu_mutex_release(&ch->dbg_s_lock);
120
121 return broadcast;
122}
123
124int gk20a_dbg_gpu_clear_broadcast_stop_trigger(struct channel_gk20a *ch)
125{
126 struct dbg_session_data *session_data;
127 struct dbg_session_gk20a *dbg_s;
128
129 gk20a_dbg(gpu_dbg_fn | gpu_dbg_gpu_dbg | gpu_dbg_intr, "");
130
131 /* guard against the session list being modified */
132 nvgpu_mutex_acquire(&ch->dbg_s_lock);
133
134 nvgpu_list_for_each_entry(session_data, &ch->dbg_s_list,
135 dbg_session_data, dbg_s_entry) {
136 dbg_s = session_data->dbg_s;
137 if (dbg_s->broadcast_stop_trigger) {
138 gk20a_dbg(gpu_dbg_gpu_dbg | gpu_dbg_fn | gpu_dbg_intr,
139 "stop trigger broadcast disabled");
140 dbg_s->broadcast_stop_trigger = false;
141 }
142 }
143
144 nvgpu_mutex_release(&ch->dbg_s_lock);
145
146 return 0;
147}
148
149int dbg_set_powergate(struct dbg_session_gk20a *dbg_s, bool disable_powergate)
150{
151 int err = 0;
152 struct gk20a *g = dbg_s->g;
153
154 /* This function must be called with g->dbg_sessions_lock held */
155
156 nvgpu_log(g, gpu_dbg_fn|gpu_dbg_gpu_dbg, "%s powergate mode = %s",
157 g->name, disable_powergate ? "disable" : "enable");
158
159 /*
160 * Powergate mode here refers to railgate+powergate+clockgate
161 * so in case slcg/blcg/elcg are disabled and railgating is enabled,
162 * disable railgating and then set is_pg_disabled = true
163 * Similarly re-enable railgating and not other features if they are not
164 * enabled when powermode=MODE_ENABLE
165 */
166 if (disable_powergate) {
167 /* save off current powergate, clk state.
168 * set gpu module's can_powergate = 0.
169 * set gpu module's clk to max.
170 * while *a* debug session is active there will be no power or
171 * clocking state changes allowed from mainline code (but they
172 * should be saved).
173 */
174 /* Allow powergate disable if the current dbg_session doesn't
175 * call a powergate disable ioctl and the global
176 * powergating_disabled_refcount is zero
177 */
178
179 if ((dbg_s->is_pg_disabled == false) &&
180 (g->dbg_powergating_disabled_refcount++ == 0)) {
181
182 nvgpu_log(g, gpu_dbg_gpu_dbg | gpu_dbg_fn,
183 "module busy");
184 err = gk20a_busy(g);
185 if (err)
186 return err;
187
188 /*do elpg disable before clock gating */
189 nvgpu_pmu_pg_global_enable(g, false);
190
191 if (g->ops.clock_gating.slcg_gr_load_gating_prod)
192 g->ops.clock_gating.slcg_gr_load_gating_prod(g,
193 false);
194 if (g->ops.clock_gating.slcg_perf_load_gating_prod)
195 g->ops.clock_gating.slcg_perf_load_gating_prod(g,
196 false);
197 if (g->ops.clock_gating.slcg_ltc_load_gating_prod)
198 g->ops.clock_gating.slcg_ltc_load_gating_prod(g,
199 false);
200
201 gr_gk20a_init_cg_mode(g, BLCG_MODE, BLCG_RUN);
202 gr_gk20a_init_cg_mode(g, ELCG_MODE, ELCG_RUN);
203 }
204
205 dbg_s->is_pg_disabled = true;
206 } else {
207 /* restore (can) powergate, clk state */
208 /* release pending exceptions to fault/be handled as usual */
209 /*TBD: ordering of these? */
210
211 /* Re-enabling powergate as no other sessions want
212 * powergate disabled and the current dbg-sessions had
213 * requested the powergate disable through ioctl
214 */
215 if (dbg_s->is_pg_disabled &&
216 --g->dbg_powergating_disabled_refcount == 0) {
217
218 if (g->elcg_enabled)
219 gr_gk20a_init_cg_mode(g, ELCG_MODE, ELCG_AUTO);
220
221 if (g->blcg_enabled)
222 gr_gk20a_init_cg_mode(g, BLCG_MODE, BLCG_AUTO);
223
224 if (g->slcg_enabled) {
225 if (g->ops.clock_gating.
226 slcg_ltc_load_gating_prod)
227 g->ops.clock_gating.
228 slcg_ltc_load_gating_prod(g,
229 g->slcg_enabled);
230 if (g->ops.clock_gating.
231 slcg_perf_load_gating_prod)
232 g->ops.clock_gating.
233 slcg_perf_load_gating_prod(g,
234 g->slcg_enabled);
235 if (g->ops.clock_gating.
236 slcg_gr_load_gating_prod)
237 g->ops.clock_gating.
238 slcg_gr_load_gating_prod(g,
239 g->slcg_enabled);
240 }
241 nvgpu_pmu_pg_global_enable(g, true);
242
243 nvgpu_log(g, gpu_dbg_gpu_dbg | gpu_dbg_fn,
244 "module idle");
245 gk20a_idle(g);
246 }
247
248 dbg_s->is_pg_disabled = false;
249 }
250
251 nvgpu_log(g, gpu_dbg_fn|gpu_dbg_gpu_dbg, "%s powergate mode = %s done",
252 g->name, disable_powergate ? "disable" : "enable");
253 return err;
254}
255
256bool nvgpu_check_and_set_global_reservation(
257 struct dbg_session_gk20a *dbg_s,
258 struct dbg_profiler_object_data *prof_obj)
259{
260 struct gk20a *g = dbg_s->g;
261
262 if (g->profiler_reservation_count == 0) {
263 g->global_profiler_reservation_held = true;
264 g->profiler_reservation_count = 1;
265 dbg_s->has_profiler_reservation = true;
266 prof_obj->has_reservation = true;
267 return true;
268 }
269 return false;
270}
271
272bool nvgpu_check_and_set_context_reservation(
273 struct dbg_session_gk20a *dbg_s,
274 struct dbg_profiler_object_data *prof_obj)
275{
276 struct gk20a *g = dbg_s->g;
277
278 /* Assumes that we've already checked that no global reservation
279 * is in effect.
280 */
281 g->profiler_reservation_count++;
282 dbg_s->has_profiler_reservation = true;
283 prof_obj->has_reservation = true;
284 return true;
285}
286
287void nvgpu_release_profiler_reservation(struct dbg_session_gk20a *dbg_s,
288 struct dbg_profiler_object_data *prof_obj)
289{
290 struct gk20a *g = dbg_s->g;
291
292 g->profiler_reservation_count--;
293 if (g->profiler_reservation_count < 0)
294 nvgpu_err(g, "Negative reservation count!");
295 dbg_s->has_profiler_reservation = false;
296 prof_obj->has_reservation = false;
297 if (prof_obj->ch == NULL)
298 g->global_profiler_reservation_held = false;
299}
300
301int gk20a_perfbuf_enable_locked(struct gk20a *g, u64 offset, u32 size)
302{
303 struct mm_gk20a *mm = &g->mm;
304 u32 virt_addr_lo;
305 u32 virt_addr_hi;
306 u32 inst_pa_page;
307 int err;
308
309 err = gk20a_busy(g);
310 if (err) {
311 nvgpu_err(g, "failed to poweron");
312 return err;
313 }
314
315 err = g->ops.mm.alloc_inst_block(g, &mm->perfbuf.inst_block);
316 if (err)
317 return err;
318
319 g->ops.mm.init_inst_block(&mm->perfbuf.inst_block, mm->perfbuf.vm, 0);
320
321 virt_addr_lo = u64_lo32(offset);
322 virt_addr_hi = u64_hi32(offset);
323
324 /* address and size are aligned to 32 bytes, the lowest bits read back
325 * as zeros */
326 gk20a_writel(g, perf_pmasys_outbase_r(), virt_addr_lo);
327 gk20a_writel(g, perf_pmasys_outbaseupper_r(),
328 perf_pmasys_outbaseupper_ptr_f(virt_addr_hi));
329 gk20a_writel(g, perf_pmasys_outsize_r(), size);
330
331 /* this field is aligned to 4K */
332 inst_pa_page = nvgpu_inst_block_addr(g, &mm->perfbuf.inst_block) >> 12;
333
334 /* A write to MEM_BLOCK triggers the block bind operation. MEM_BLOCK
335 * should be written last */
336 gk20a_writel(g, perf_pmasys_mem_block_r(),
337 perf_pmasys_mem_block_base_f(inst_pa_page) |
338 perf_pmasys_mem_block_valid_true_f() |
339 perf_pmasys_mem_block_target_lfb_f());
340
341 gk20a_idle(g);
342 return 0;
343}
344
345/* must be called with dbg_sessions_lock held */
346int gk20a_perfbuf_disable_locked(struct gk20a *g)
347{
348 int err = gk20a_busy(g);
349 if (err) {
350 nvgpu_err(g, "failed to poweron");
351 return err;
352 }
353
354 gk20a_writel(g, perf_pmasys_outbase_r(), 0);
355 gk20a_writel(g, perf_pmasys_outbaseupper_r(),
356 perf_pmasys_outbaseupper_ptr_f(0));
357 gk20a_writel(g, perf_pmasys_outsize_r(), 0);
358
359 gk20a_writel(g, perf_pmasys_mem_block_r(),
360 perf_pmasys_mem_block_base_f(0) |
361 perf_pmasys_mem_block_valid_false_f() |
362 perf_pmasys_mem_block_target_f(0));
363
364 gk20a_idle(g);
365
366 return 0;
367}