aboutsummaryrefslogtreecommitdiffstats
path: root/include/os/linux/linux-channel.c
diff options
context:
space:
mode:
Diffstat (limited to 'include/os/linux/linux-channel.c')
-rw-r--r--include/os/linux/linux-channel.c657
1 files changed, 0 insertions, 657 deletions
diff --git a/include/os/linux/linux-channel.c b/include/os/linux/linux-channel.c
deleted file mode 100644
index d035baf..0000000
--- a/include/os/linux/linux-channel.c
+++ /dev/null
@@ -1,657 +0,0 @@
1/*
2 * Copyright (c) 2017-2018, NVIDIA Corporation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <nvgpu/enabled.h>
18#include <nvgpu/debug.h>
19#include <nvgpu/error_notifier.h>
20#include <nvgpu/os_sched.h>
21#include <nvgpu/gk20a.h>
22#include <nvgpu/channel.h>
23#include <nvgpu/dma.h>
24
25/*
26 * This is required for nvgpu_vm_find_buf() which is used in the tracing
27 * code. Once we can get and access userspace buffers without requiring
28 * direct dma_buf usage this can be removed.
29 */
30#include <nvgpu/linux/vm.h>
31
32#include "channel.h"
33#include "ioctl_channel.h"
34#include "os_linux.h"
35#include "dmabuf.h"
36
37#include <nvgpu/hw/gk20a/hw_pbdma_gk20a.h>
38
39#include <linux/uaccess.h>
40#include <linux/dma-buf.h>
41#include <trace/events/gk20a.h>
42#include <uapi/linux/nvgpu.h>
43
44#include "sync_sema_android.h"
45
46u32 nvgpu_submit_gpfifo_user_flags_to_common_flags(u32 user_flags)
47{
48 u32 flags = 0;
49
50 if (user_flags & NVGPU_SUBMIT_GPFIFO_FLAGS_FENCE_WAIT)
51 flags |= NVGPU_SUBMIT_FLAGS_FENCE_WAIT;
52
53 if (user_flags & NVGPU_SUBMIT_GPFIFO_FLAGS_FENCE_GET)
54 flags |= NVGPU_SUBMIT_FLAGS_FENCE_GET;
55
56 if (user_flags & NVGPU_SUBMIT_GPFIFO_FLAGS_HW_FORMAT)
57 flags |= NVGPU_SUBMIT_FLAGS_HW_FORMAT;
58
59 if (user_flags & NVGPU_SUBMIT_GPFIFO_FLAGS_SYNC_FENCE)
60 flags |= NVGPU_SUBMIT_FLAGS_SYNC_FENCE;
61
62 if (user_flags & NVGPU_SUBMIT_GPFIFO_FLAGS_SUPPRESS_WFI)
63 flags |= NVGPU_SUBMIT_FLAGS_SUPPRESS_WFI;
64
65 if (user_flags & NVGPU_SUBMIT_GPFIFO_FLAGS_SKIP_BUFFER_REFCOUNTING)
66 flags |= NVGPU_SUBMIT_FLAGS_SKIP_BUFFER_REFCOUNTING;
67
68 return flags;
69}
70
71/*
72 * API to convert error_notifiers in common code and of the form
73 * NVGPU_ERR_NOTIFIER_* into Linux specific error_notifiers exposed to user
74 * space and of the form NVGPU_CHANNEL_*
75 */
76static u32 nvgpu_error_notifier_to_channel_notifier(u32 error_notifier)
77{
78 switch (error_notifier) {
79 case NVGPU_ERR_NOTIFIER_FIFO_ERROR_IDLE_TIMEOUT:
80 return NVGPU_CHANNEL_FIFO_ERROR_IDLE_TIMEOUT;
81 case NVGPU_ERR_NOTIFIER_GR_ERROR_SW_METHOD:
82 return NVGPU_CHANNEL_GR_ERROR_SW_METHOD;
83 case NVGPU_ERR_NOTIFIER_GR_ERROR_SW_NOTIFY:
84 return NVGPU_CHANNEL_GR_ERROR_SW_NOTIFY;
85 case NVGPU_ERR_NOTIFIER_GR_EXCEPTION:
86 return NVGPU_CHANNEL_GR_EXCEPTION;
87 case NVGPU_ERR_NOTIFIER_GR_SEMAPHORE_TIMEOUT:
88 return NVGPU_CHANNEL_GR_SEMAPHORE_TIMEOUT;
89 case NVGPU_ERR_NOTIFIER_GR_ILLEGAL_NOTIFY:
90 return NVGPU_CHANNEL_GR_ILLEGAL_NOTIFY;
91 case NVGPU_ERR_NOTIFIER_FIFO_ERROR_MMU_ERR_FLT:
92 return NVGPU_CHANNEL_FIFO_ERROR_MMU_ERR_FLT;
93 case NVGPU_ERR_NOTIFIER_PBDMA_ERROR:
94 return NVGPU_CHANNEL_PBDMA_ERROR;
95 case NVGPU_ERR_NOTIFIER_FECS_ERR_UNIMP_FIRMWARE_METHOD:
96 return NVGPU_CHANNEL_FECS_ERR_UNIMP_FIRMWARE_METHOD;
97 case NVGPU_ERR_NOTIFIER_RESETCHANNEL_VERIF_ERROR:
98 return NVGPU_CHANNEL_RESETCHANNEL_VERIF_ERROR;
99 case NVGPU_ERR_NOTIFIER_PBDMA_PUSHBUFFER_CRC_MISMATCH:
100 return NVGPU_CHANNEL_PBDMA_PUSHBUFFER_CRC_MISMATCH;
101 }
102
103 pr_warn("%s: invalid error_notifier requested %u\n", __func__, error_notifier);
104
105 return error_notifier;
106}
107
108/**
109 * nvgpu_set_error_notifier_locked()
110 * Should be called with ch->error_notifier_mutex held
111 *
112 * error should be of the form NVGPU_ERR_NOTIFIER_*
113 */
114void nvgpu_set_error_notifier_locked(struct channel_gk20a *ch, u32 error)
115{
116 struct nvgpu_channel_linux *priv = ch->os_priv;
117
118 error = nvgpu_error_notifier_to_channel_notifier(error);
119
120 if (priv->error_notifier.dmabuf) {
121 struct nvgpu_notification *notification =
122 priv->error_notifier.notification;
123 struct timespec time_data;
124 u64 nsec;
125
126 getnstimeofday(&time_data);
127 nsec = ((u64)time_data.tv_sec) * 1000000000u +
128 (u64)time_data.tv_nsec;
129 notification->time_stamp.nanoseconds[0] =
130 (u32)nsec;
131 notification->time_stamp.nanoseconds[1] =
132 (u32)(nsec >> 32);
133 notification->info32 = error;
134 notification->status = 0xffff;
135
136 nvgpu_err(ch->g,
137 "error notifier set to %d for ch %d", error, ch->chid);
138 }
139}
140
141/* error should be of the form NVGPU_ERR_NOTIFIER_* */
142void nvgpu_set_error_notifier(struct channel_gk20a *ch, u32 error)
143{
144 struct nvgpu_channel_linux *priv = ch->os_priv;
145
146 nvgpu_mutex_acquire(&priv->error_notifier.mutex);
147 nvgpu_set_error_notifier_locked(ch, error);
148 nvgpu_mutex_release(&priv->error_notifier.mutex);
149}
150
151void nvgpu_set_error_notifier_if_empty(struct channel_gk20a *ch, u32 error)
152{
153 struct nvgpu_channel_linux *priv = ch->os_priv;
154
155 nvgpu_mutex_acquire(&priv->error_notifier.mutex);
156 if (priv->error_notifier.dmabuf) {
157 struct nvgpu_notification *notification =
158 priv->error_notifier.notification;
159
160 /* Don't overwrite error flag if it is already set */
161 if (notification->status != 0xffff)
162 nvgpu_set_error_notifier_locked(ch, error);
163 }
164 nvgpu_mutex_release(&priv->error_notifier.mutex);
165}
166
167/* error_notifier should be of the form NVGPU_ERR_NOTIFIER_* */
168bool nvgpu_is_error_notifier_set(struct channel_gk20a *ch, u32 error_notifier)
169{
170 struct nvgpu_channel_linux *priv = ch->os_priv;
171 bool notifier_set = false;
172
173 error_notifier = nvgpu_error_notifier_to_channel_notifier(error_notifier);
174
175 nvgpu_mutex_acquire(&priv->error_notifier.mutex);
176 if (priv->error_notifier.dmabuf) {
177 struct nvgpu_notification *notification =
178 priv->error_notifier.notification;
179 u32 err = notification->info32;
180
181 if (err == error_notifier)
182 notifier_set = true;
183 }
184 nvgpu_mutex_release(&priv->error_notifier.mutex);
185
186 return notifier_set;
187}
188
189static void gk20a_channel_update_runcb_fn(struct work_struct *work)
190{
191 struct nvgpu_channel_completion_cb *completion_cb =
192 container_of(work, struct nvgpu_channel_completion_cb, work);
193 struct nvgpu_channel_linux *priv =
194 container_of(completion_cb,
195 struct nvgpu_channel_linux, completion_cb);
196 struct channel_gk20a *ch = priv->ch;
197 void (*fn)(struct channel_gk20a *, void *);
198 void *user_data;
199
200 nvgpu_spinlock_acquire(&completion_cb->lock);
201 fn = completion_cb->fn;
202 user_data = completion_cb->user_data;
203 nvgpu_spinlock_release(&completion_cb->lock);
204
205 if (fn)
206 fn(ch, user_data);
207}
208
209static void nvgpu_channel_work_completion_init(struct channel_gk20a *ch)
210{
211 struct nvgpu_channel_linux *priv = ch->os_priv;
212
213 priv->completion_cb.fn = NULL;
214 priv->completion_cb.user_data = NULL;
215 nvgpu_spinlock_init(&priv->completion_cb.lock);
216 INIT_WORK(&priv->completion_cb.work, gk20a_channel_update_runcb_fn);
217}
218
219static void nvgpu_channel_work_completion_clear(struct channel_gk20a *ch)
220{
221 struct nvgpu_channel_linux *priv = ch->os_priv;
222
223 nvgpu_spinlock_acquire(&priv->completion_cb.lock);
224 priv->completion_cb.fn = NULL;
225 priv->completion_cb.user_data = NULL;
226 nvgpu_spinlock_release(&priv->completion_cb.lock);
227 cancel_work_sync(&priv->completion_cb.work);
228}
229
230static void nvgpu_channel_work_completion_signal(struct channel_gk20a *ch)
231{
232 struct nvgpu_channel_linux *priv = ch->os_priv;
233
234 if (priv->completion_cb.fn)
235 schedule_work(&priv->completion_cb.work);
236}
237
238static void nvgpu_channel_work_completion_cancel_sync(struct channel_gk20a *ch)
239{
240 struct nvgpu_channel_linux *priv = ch->os_priv;
241
242 if (priv->completion_cb.fn)
243 cancel_work_sync(&priv->completion_cb.work);
244}
245
246struct channel_gk20a *gk20a_open_new_channel_with_cb(struct gk20a *g,
247 void (*update_fn)(struct channel_gk20a *, void *),
248 void *update_fn_data,
249 int runlist_id,
250 bool is_privileged_channel)
251{
252 struct channel_gk20a *ch;
253 struct nvgpu_channel_linux *priv;
254
255 ch = gk20a_open_new_channel(g, runlist_id, is_privileged_channel,
256 nvgpu_current_pid(g), nvgpu_current_tid(g));
257
258 if (ch) {
259 priv = ch->os_priv;
260 nvgpu_spinlock_acquire(&priv->completion_cb.lock);
261 priv->completion_cb.fn = update_fn;
262 priv->completion_cb.user_data = update_fn_data;
263 nvgpu_spinlock_release(&priv->completion_cb.lock);
264 }
265
266 return ch;
267}
268
269static void nvgpu_channel_open_linux(struct channel_gk20a *ch)
270{
271}
272
273static void nvgpu_channel_close_linux(struct channel_gk20a *ch)
274{
275 nvgpu_channel_work_completion_clear(ch);
276
277#if defined(CONFIG_GK20A_CYCLE_STATS)
278 gk20a_channel_free_cycle_stats_buffer(ch);
279 gk20a_channel_free_cycle_stats_snapshot(ch);
280#endif
281}
282
283static int nvgpu_channel_alloc_linux(struct gk20a *g, struct channel_gk20a *ch)
284{
285 struct nvgpu_channel_linux *priv;
286 int err;
287
288 priv = nvgpu_kzalloc(g, sizeof(*priv));
289 if (!priv)
290 return -ENOMEM;
291
292 ch->os_priv = priv;
293 priv->ch = ch;
294
295#ifdef CONFIG_SYNC
296 ch->has_os_fence_framework_support = true;
297#endif
298
299 err = nvgpu_mutex_init(&priv->error_notifier.mutex);
300 if (err) {
301 nvgpu_kfree(g, priv);
302 return err;
303 }
304
305 nvgpu_channel_work_completion_init(ch);
306
307 return 0;
308}
309
310static void nvgpu_channel_free_linux(struct gk20a *g, struct channel_gk20a *ch)
311{
312 struct nvgpu_channel_linux *priv = ch->os_priv;
313
314 nvgpu_mutex_destroy(&priv->error_notifier.mutex);
315 nvgpu_kfree(g, priv);
316
317 ch->os_priv = NULL;
318
319#ifdef CONFIG_SYNC
320 ch->has_os_fence_framework_support = false;
321#endif
322}
323
324static int nvgpu_channel_init_os_fence_framework(struct channel_gk20a *ch,
325 const char *fmt, ...)
326{
327 struct nvgpu_channel_linux *priv = ch->os_priv;
328 struct nvgpu_os_fence_framework *fence_framework;
329 char name[30];
330 va_list args;
331
332 fence_framework = &priv->fence_framework;
333
334 va_start(args, fmt);
335 vsnprintf(name, sizeof(name), fmt, args);
336 va_end(args);
337
338 fence_framework->timeline = gk20a_sync_timeline_create(name);
339
340 if (!fence_framework->timeline)
341 return -EINVAL;
342
343 return 0;
344}
345static void nvgpu_channel_signal_os_fence_framework(struct channel_gk20a *ch)
346{
347 struct nvgpu_channel_linux *priv = ch->os_priv;
348 struct nvgpu_os_fence_framework *fence_framework;
349
350 fence_framework = &priv->fence_framework;
351
352 gk20a_sync_timeline_signal(fence_framework->timeline);
353}
354
355static void nvgpu_channel_destroy_os_fence_framework(struct channel_gk20a *ch)
356{
357 struct nvgpu_channel_linux *priv = ch->os_priv;
358 struct nvgpu_os_fence_framework *fence_framework;
359
360 fence_framework = &priv->fence_framework;
361
362 gk20a_sync_timeline_destroy(fence_framework->timeline);
363 fence_framework->timeline = NULL;
364}
365
366static bool nvgpu_channel_fence_framework_exists(struct channel_gk20a *ch)
367{
368 struct nvgpu_channel_linux *priv = ch->os_priv;
369 struct nvgpu_os_fence_framework *fence_framework;
370
371 fence_framework = &priv->fence_framework;
372
373 return (fence_framework->timeline != NULL);
374}
375
376static int nvgpu_channel_copy_user_gpfifo(struct nvgpu_gpfifo_entry *dest,
377 struct nvgpu_gpfifo_userdata userdata, u32 start, u32 length)
378{
379 struct nvgpu_gpfifo_entry __user *user_gpfifo = userdata.entries;
380 unsigned long n;
381
382 n = copy_from_user(dest, user_gpfifo + start,
383 length * sizeof(struct nvgpu_gpfifo_entry));
384
385 return n == 0 ? 0 : -EFAULT;
386}
387
388int nvgpu_usermode_buf_from_dmabuf(struct gk20a *g, int dmabuf_fd,
389 struct nvgpu_mem *mem, struct nvgpu_usermode_buf_linux *buf)
390{
391 struct device *dev = dev_from_gk20a(g);
392 struct dma_buf *dmabuf;
393 struct sg_table *sgt;
394 struct dma_buf_attachment *attachment;
395 int err;
396
397 dmabuf = dma_buf_get(dmabuf_fd);
398 if (IS_ERR(dmabuf)) {
399 return PTR_ERR(dmabuf);
400 }
401
402 if (gk20a_dmabuf_aperture(g, dmabuf) == APERTURE_INVALID) {
403 err = -EINVAL;
404 goto put_dmabuf;
405 }
406
407 err = gk20a_dmabuf_alloc_drvdata(dmabuf, dev);
408 if (err != 0) {
409 goto put_dmabuf;
410 }
411
412 sgt = gk20a_mm_pin(dev, dmabuf, &attachment);
413 if (IS_ERR(sgt)) {
414 nvgpu_warn(g, "Failed to pin dma_buf!");
415 err = PTR_ERR(sgt);
416 goto put_dmabuf;
417 }
418
419 buf->dmabuf = dmabuf;
420 buf->attachment = attachment;
421 buf->sgt = sgt;
422
423 /*
424 * This mem is unmapped and freed in a common path; for Linux, we'll
425 * also need to unref the dmabuf stuff (above) but the sgt here is only
426 * borrowed, so it cannot be freed by nvgpu_mem_*.
427 */
428 mem->mem_flags = NVGPU_MEM_FLAG_FOREIGN_SGT;
429 mem->aperture = APERTURE_SYSMEM;
430 mem->skip_wmb = 0;
431 mem->size = dmabuf->size;
432
433 mem->priv.flags = 0;
434 mem->priv.pages = NULL;
435 mem->priv.sgt = sgt;
436
437 return 0;
438put_dmabuf:
439 dma_buf_put(dmabuf);
440 return err;
441}
442
443void nvgpu_channel_free_usermode_buffers(struct channel_gk20a *c)
444{
445 struct nvgpu_channel_linux *priv = c->os_priv;
446 struct gk20a *g = c->g;
447 struct device *dev = dev_from_gk20a(g);
448
449 if (priv->usermode.gpfifo.dmabuf != NULL) {
450 gk20a_mm_unpin(dev, priv->usermode.gpfifo.dmabuf,
451 priv->usermode.gpfifo.attachment,
452 priv->usermode.gpfifo.sgt);
453 dma_buf_put(priv->usermode.gpfifo.dmabuf);
454 priv->usermode.gpfifo.dmabuf = NULL;
455 }
456
457 if (priv->usermode.userd.dmabuf != NULL) {
458 gk20a_mm_unpin(dev, priv->usermode.userd.dmabuf,
459 priv->usermode.userd.attachment,
460 priv->usermode.userd.sgt);
461 dma_buf_put(priv->usermode.userd.dmabuf);
462 priv->usermode.userd.dmabuf = NULL;
463 }
464}
465
466static int nvgpu_channel_alloc_usermode_buffers(struct channel_gk20a *c,
467 struct nvgpu_setup_bind_args *args)
468{
469 struct nvgpu_channel_linux *priv = c->os_priv;
470 struct gk20a *g = c->g;
471 struct device *dev = dev_from_gk20a(g);
472 size_t gpfifo_size;
473 int err;
474
475 if (args->gpfifo_dmabuf_fd == 0 || args->userd_dmabuf_fd == 0) {
476 return -EINVAL;
477 }
478
479 if (args->gpfifo_dmabuf_offset != 0 ||
480 args->userd_dmabuf_offset != 0) {
481 /* TODO - not yet supported */
482 return -EINVAL;
483 }
484
485 err = nvgpu_usermode_buf_from_dmabuf(g, args->gpfifo_dmabuf_fd,
486 &c->usermode_gpfifo, &priv->usermode.gpfifo);
487 if (err < 0) {
488 return err;
489 }
490
491 gpfifo_size = max_t(u32, SZ_4K,
492 args->num_gpfifo_entries *
493 nvgpu_get_gpfifo_entry_size());
494
495 if (c->usermode_gpfifo.size < gpfifo_size) {
496 err = -EINVAL;
497 goto free_gpfifo;
498 }
499
500 c->usermode_gpfifo.gpu_va = nvgpu_gmmu_map(c->vm, &c->usermode_gpfifo,
501 c->usermode_gpfifo.size, 0, gk20a_mem_flag_none,
502 false, c->usermode_gpfifo.aperture);
503
504 if (c->usermode_gpfifo.gpu_va == 0) {
505 err = -ENOMEM;
506 goto unmap_free_gpfifo;
507 }
508
509 err = nvgpu_usermode_buf_from_dmabuf(g, args->userd_dmabuf_fd,
510 &c->usermode_userd, &priv->usermode.userd);
511 if (err < 0) {
512 goto unmap_free_gpfifo;
513 }
514
515 args->work_submit_token = g->fifo.channel_base + c->chid;
516
517 return 0;
518unmap_free_gpfifo:
519 nvgpu_dma_unmap_free(c->vm, &c->usermode_gpfifo);
520free_gpfifo:
521 gk20a_mm_unpin(dev, priv->usermode.gpfifo.dmabuf,
522 priv->usermode.gpfifo.attachment,
523 priv->usermode.gpfifo.sgt);
524 dma_buf_put(priv->usermode.gpfifo.dmabuf);
525 priv->usermode.gpfifo.dmabuf = NULL;
526 return err;
527}
528
529int nvgpu_init_channel_support_linux(struct nvgpu_os_linux *l)
530{
531 struct gk20a *g = &l->g;
532 struct fifo_gk20a *f = &g->fifo;
533 int chid;
534 int err;
535
536 for (chid = 0; chid < (int)f->num_channels; chid++) {
537 struct channel_gk20a *ch = &f->channel[chid];
538
539 err = nvgpu_channel_alloc_linux(g, ch);
540 if (err)
541 goto err_clean;
542 }
543
544 g->os_channel.open = nvgpu_channel_open_linux;
545 g->os_channel.close = nvgpu_channel_close_linux;
546 g->os_channel.work_completion_signal =
547 nvgpu_channel_work_completion_signal;
548 g->os_channel.work_completion_cancel_sync =
549 nvgpu_channel_work_completion_cancel_sync;
550
551 g->os_channel.os_fence_framework_inst_exists =
552 nvgpu_channel_fence_framework_exists;
553 g->os_channel.init_os_fence_framework =
554 nvgpu_channel_init_os_fence_framework;
555 g->os_channel.signal_os_fence_framework =
556 nvgpu_channel_signal_os_fence_framework;
557 g->os_channel.destroy_os_fence_framework =
558 nvgpu_channel_destroy_os_fence_framework;
559
560 g->os_channel.copy_user_gpfifo =
561 nvgpu_channel_copy_user_gpfifo;
562
563 g->os_channel.alloc_usermode_buffers =
564 nvgpu_channel_alloc_usermode_buffers;
565
566 g->os_channel.free_usermode_buffers =
567 nvgpu_channel_free_usermode_buffers;
568
569 return 0;
570
571err_clean:
572 for (; chid >= 0; chid--) {
573 struct channel_gk20a *ch = &f->channel[chid];
574
575 nvgpu_channel_free_linux(g, ch);
576 }
577 return err;
578}
579
580void nvgpu_remove_channel_support_linux(struct nvgpu_os_linux *l)
581{
582 struct gk20a *g = &l->g;
583 struct fifo_gk20a *f = &g->fifo;
584 unsigned int chid;
585
586 for (chid = 0; chid < f->num_channels; chid++) {
587 struct channel_gk20a *ch = &f->channel[chid];
588
589 nvgpu_channel_free_linux(g, ch);
590 }
591
592 g->os_channel.os_fence_framework_inst_exists = NULL;
593 g->os_channel.init_os_fence_framework = NULL;
594 g->os_channel.signal_os_fence_framework = NULL;
595 g->os_channel.destroy_os_fence_framework = NULL;
596}
597
598u32 nvgpu_get_gpfifo_entry_size(void)
599{
600 return sizeof(struct nvgpu_gpfifo_entry);
601}
602
603#ifdef CONFIG_DEBUG_FS
604static void trace_write_pushbuffer(struct channel_gk20a *c,
605 struct nvgpu_gpfifo_entry *g)
606{
607 void *mem = NULL;
608 unsigned int words;
609 u64 offset;
610 struct dma_buf *dmabuf = NULL;
611
612 if (gk20a_debug_trace_cmdbuf) {
613 u64 gpu_va = (u64)g->entry0 |
614 (u64)((u64)pbdma_gp_entry1_get_hi_v(g->entry1) << 32);
615 int err;
616
617 words = pbdma_gp_entry1_length_v(g->entry1);
618 err = nvgpu_vm_find_buf(c->vm, gpu_va, &dmabuf, &offset);
619 if (!err)
620 mem = dma_buf_vmap(dmabuf);
621 }
622
623 if (mem) {
624 u32 i;
625 /*
626 * Write in batches of 128 as there seems to be a limit
627 * of how much you can output to ftrace at once.
628 */
629 for (i = 0; i < words; i += 128U) {
630 trace_gk20a_push_cmdbuf(
631 c->g->name,
632 0,
633 min(words - i, 128U),
634 offset + i * sizeof(u32),
635 mem);
636 }
637 dma_buf_vunmap(dmabuf, mem);
638 }
639}
640
641void trace_write_pushbuffers(struct channel_gk20a *c, u32 count)
642{
643 struct nvgpu_gpfifo_entry *gp = c->gpfifo.mem.cpu_va;
644 u32 n = c->gpfifo.entry_num;
645 u32 start = c->gpfifo.put;
646 u32 i;
647
648 if (!gk20a_debug_trace_cmdbuf)
649 return;
650
651 if (!gp)
652 return;
653
654 for (i = 0; i < count; i++)
655 trace_write_pushbuffer(c, &gp[(start + i) % n]);
656}
657#endif