diff options
author | Konsta Holtta <kholtta@nvidia.com> | 2018-09-11 07:47:51 -0400 |
---|---|---|
committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2019-08-15 03:58:54 -0400 |
commit | 8b484c0b531b95fce024e101cdd204f1f8107c29 (patch) | |
tree | d55f5ab0ed32e8c45ecfb9fa639456eba5433de2 /drivers/gpu/nvgpu/os/linux | |
parent | 758cb76e225775ba5ac3dd2cb9415cb40dc83810 (diff) |
gpu: nvgpu: support usermode submit buffers
Import userd and gpfifo buffers from userspace if provided via
NVGPU_IOCTL_CHANNEL_ALLOC_GPFIFO_EX. Also supply the work submit token
(i.e., the hw channel id) to userspace.
To keep the buffers alive, store their dmabuf and attachment/sgt handles
in nvgpu_channel_linux. Our nvgpu_mem doesn't provide such data for
buffers that are mainly in kernel use. The buffers are freed via a new
API in the os_channel interface.
Fix a bug in gk20a_channel_free_usermode_buffers: also unmap the
usermode gpfifo buffer.
Bug 200145225
Bug 200541476
Change-Id: I8416af7085c91b044ac8ccd9faa38e2a6d0c3946
Signed-off-by: Konsta Holtta <kholtta@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1795821
Signed-off-by: Debarshi Dutta <ddutta@nvidia.com>
(cherry picked from commit 99b1c6dcdf328efcfe47338ad1b71a114ab7f272
in dev-main)
Reviewed-on: https://git-master.nvidia.com/r/2170603
GVS: Gerrit_Virtual_Submit
Reviewed-by: Bibek Basu <bbasu@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/os/linux')
-rw-r--r-- | drivers/gpu/nvgpu/os/linux/channel.h | 15 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/os/linux/ioctl_channel.c | 13 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/os/linux/linux-channel.c | 149 |
3 files changed, 177 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/os/linux/channel.h b/drivers/gpu/nvgpu/os/linux/channel.h index 2210678d..e6326fad 100644 --- a/drivers/gpu/nvgpu/os/linux/channel.h +++ b/drivers/gpu/nvgpu/os/linux/channel.h | |||
@@ -63,6 +63,19 @@ struct nvgpu_os_fence_framework { | |||
63 | struct sync_timeline *timeline; | 63 | struct sync_timeline *timeline; |
64 | }; | 64 | }; |
65 | 65 | ||
66 | struct nvgpu_usermode_bufs_linux { | ||
67 | /* | ||
68 | * Common low level info of these is stored in nvgpu_mems in | ||
69 | * channel_gk20a; these hold lifetimes for the actual dmabuf and its | ||
70 | * dma mapping. | ||
71 | */ | ||
72 | struct nvgpu_usermode_buf_linux { | ||
73 | struct dma_buf *dmabuf; | ||
74 | struct dma_buf_attachment *attachment; | ||
75 | struct sg_table *sgt; | ||
76 | } gpfifo, userd; | ||
77 | }; | ||
78 | |||
66 | struct nvgpu_channel_linux { | 79 | struct nvgpu_channel_linux { |
67 | struct channel_gk20a *ch; | 80 | struct channel_gk20a *ch; |
68 | 81 | ||
@@ -72,6 +85,8 @@ struct nvgpu_channel_linux { | |||
72 | struct nvgpu_error_notifier error_notifier; | 85 | struct nvgpu_error_notifier error_notifier; |
73 | 86 | ||
74 | struct dma_buf *cyclestate_buffer_handler; | 87 | struct dma_buf *cyclestate_buffer_handler; |
88 | |||
89 | struct nvgpu_usermode_bufs_linux usermode; | ||
75 | }; | 90 | }; |
76 | 91 | ||
77 | u32 nvgpu_submit_gpfifo_user_flags_to_common_flags(u32 user_flags); | 92 | u32 nvgpu_submit_gpfifo_user_flags_to_common_flags(u32 user_flags); |
diff --git a/drivers/gpu/nvgpu/os/linux/ioctl_channel.c b/drivers/gpu/nvgpu/os/linux/ioctl_channel.c index d243c425..22177171 100644 --- a/drivers/gpu/nvgpu/os/linux/ioctl_channel.c +++ b/drivers/gpu/nvgpu/os/linux/ioctl_channel.c | |||
@@ -590,6 +590,9 @@ static u32 nvgpu_setup_bind_user_flags_to_common_flags(u32 user_flags) | |||
590 | if (user_flags & NVGPU_CHANNEL_SETUP_BIND_FLAGS_REPLAYABLE_FAULTS_ENABLE) | 590 | if (user_flags & NVGPU_CHANNEL_SETUP_BIND_FLAGS_REPLAYABLE_FAULTS_ENABLE) |
591 | flags |= NVGPU_SETUP_BIND_FLAGS_REPLAYABLE_FAULTS_ENABLE; | 591 | flags |= NVGPU_SETUP_BIND_FLAGS_REPLAYABLE_FAULTS_ENABLE; |
592 | 592 | ||
593 | if (user_flags & NVGPU_CHANNEL_SETUP_BIND_FLAGS_USERMODE_SUPPORT) | ||
594 | flags |= NVGPU_SETUP_BIND_FLAGS_USERMODE_SUPPORT; | ||
595 | |||
593 | return flags; | 596 | return flags; |
594 | } | 597 | } |
595 | 598 | ||
@@ -601,6 +604,14 @@ static void nvgpu_get_setup_bind_args( | |||
601 | channel_setup_bind_args->num_gpfifo_entries; | 604 | channel_setup_bind_args->num_gpfifo_entries; |
602 | setup_bind_args->num_inflight_jobs = | 605 | setup_bind_args->num_inflight_jobs = |
603 | channel_setup_bind_args->num_inflight_jobs; | 606 | channel_setup_bind_args->num_inflight_jobs; |
607 | setup_bind_args->userd_dmabuf_fd = | ||
608 | channel_setup_bind_args->userd_dmabuf_fd; | ||
609 | setup_bind_args->userd_dmabuf_offset = | ||
610 | channel_setup_bind_args->userd_dmabuf_offset; | ||
611 | setup_bind_args->gpfifo_dmabuf_fd = | ||
612 | channel_setup_bind_args->gpfifo_dmabuf_fd; | ||
613 | setup_bind_args->gpfifo_dmabuf_offset = | ||
614 | channel_setup_bind_args->gpfifo_dmabuf_offset; | ||
604 | setup_bind_args->flags = nvgpu_setup_bind_user_flags_to_common_flags( | 615 | setup_bind_args->flags = nvgpu_setup_bind_user_flags_to_common_flags( |
605 | channel_setup_bind_args->flags); | 616 | channel_setup_bind_args->flags); |
606 | } | 617 | } |
@@ -1156,6 +1167,8 @@ long gk20a_channel_ioctl(struct file *filp, | |||
1156 | break; | 1167 | break; |
1157 | } | 1168 | } |
1158 | err = nvgpu_channel_setup_bind(ch, &setup_bind_args); | 1169 | err = nvgpu_channel_setup_bind(ch, &setup_bind_args); |
1170 | channel_setup_bind_args->work_submit_token = | ||
1171 | setup_bind_args.work_submit_token; | ||
1159 | gk20a_idle(ch->g); | 1172 | gk20a_idle(ch->g); |
1160 | break; | 1173 | break; |
1161 | } | 1174 | } |
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 | ||
388 | int 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; | ||
438 | put_dmabuf: | ||
439 | dma_buf_put(dmabuf); | ||
440 | return err; | ||
441 | } | ||
442 | |||
443 | void 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 | |||
466 | static 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; | ||
518 | unmap_free_gpfifo: | ||
519 | nvgpu_dma_unmap_free(c->vm, &c->usermode_gpfifo); | ||
520 | free_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 | |||
386 | int nvgpu_init_channel_support_linux(struct nvgpu_os_linux *l) | 529 | int 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 | ||
422 | err_clean: | 571 | err_clean: |