summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/os/linux/linux-channel.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/os/linux/linux-channel.c')
-rw-r--r--drivers/gpu/nvgpu/os/linux/linux-channel.c149
1 files changed, 149 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/os/linux/linux-channel.c b/drivers/gpu/nvgpu/os/linux/linux-channel.c
index 1fec3604..d035baf7 100644
--- a/drivers/gpu/nvgpu/os/linux/linux-channel.c
+++ b/drivers/gpu/nvgpu/os/linux/linux-channel.c
@@ -20,6 +20,7 @@
20#include <nvgpu/os_sched.h> 20#include <nvgpu/os_sched.h>
21#include <nvgpu/gk20a.h> 21#include <nvgpu/gk20a.h>
22#include <nvgpu/channel.h> 22#include <nvgpu/channel.h>
23#include <nvgpu/dma.h>
23 24
24/* 25/*
25 * This is required for nvgpu_vm_find_buf() which is used in the tracing 26 * This is required for nvgpu_vm_find_buf() which is used in the tracing
@@ -31,6 +32,7 @@
31#include "channel.h" 32#include "channel.h"
32#include "ioctl_channel.h" 33#include "ioctl_channel.h"
33#include "os_linux.h" 34#include "os_linux.h"
35#include "dmabuf.h"
34 36
35#include <nvgpu/hw/gk20a/hw_pbdma_gk20a.h> 37#include <nvgpu/hw/gk20a/hw_pbdma_gk20a.h>
36 38
@@ -383,6 +385,147 @@ static int nvgpu_channel_copy_user_gpfifo(struct nvgpu_gpfifo_entry *dest,
383 return n == 0 ? 0 : -EFAULT; 385 return n == 0 ? 0 : -EFAULT;
384} 386}
385 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
386int nvgpu_init_channel_support_linux(struct nvgpu_os_linux *l) 529int nvgpu_init_channel_support_linux(struct nvgpu_os_linux *l)
387{ 530{
388 struct gk20a *g = &l->g; 531 struct gk20a *g = &l->g;
@@ -417,6 +560,12 @@ int nvgpu_init_channel_support_linux(struct nvgpu_os_linux *l)
417 g->os_channel.copy_user_gpfifo = 560 g->os_channel.copy_user_gpfifo =
418 nvgpu_channel_copy_user_gpfifo; 561 nvgpu_channel_copy_user_gpfifo;
419 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
420 return 0; 569 return 0;
421 570
422err_clean: 571err_clean: