diff options
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap_alloc.c | 86 | ||||
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap_dev.c | 4 | ||||
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap_dmabuf.c | 11 | ||||
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap_ioctl.c | 13 | ||||
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap_ioctl.h | 2 | ||||
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap_priv.h | 8 |
6 files changed, 111 insertions, 13 deletions
diff --git a/drivers/video/tegra/nvmap/nvmap_alloc.c b/drivers/video/tegra/nvmap/nvmap_alloc.c index 74c9e4b90..ea648b8bf 100644 --- a/drivers/video/tegra/nvmap/nvmap_alloc.c +++ b/drivers/video/tegra/nvmap/nvmap_alloc.c | |||
@@ -775,6 +775,7 @@ int nvmap_alloc_handle(struct nvmap_client *client, | |||
775 | nvmap_stats_read(NS_TOTAL), | 775 | nvmap_stats_read(NS_TOTAL), |
776 | nvmap_stats_read(NS_ALLOC)); | 776 | nvmap_stats_read(NS_ALLOC)); |
777 | h->userflags = flags; | 777 | h->userflags = flags; |
778 | h->userheap_mask = heap_mask; | ||
778 | nr_page = ((h->size + PAGE_SIZE - 1) >> PAGE_SHIFT); | 779 | nr_page = ((h->size + PAGE_SIZE - 1) >> PAGE_SHIFT); |
779 | /* Force mapping to uncached for VPR memory. */ | 780 | /* Force mapping to uncached for VPR memory. */ |
780 | if (heap_mask & (NVMAP_HEAP_CARVEOUT_VPR | ~nvmap_dev->cpu_access_mask)) | 781 | if (heap_mask & (NVMAP_HEAP_CARVEOUT_VPR | ~nvmap_dev->cpu_access_mask)) |
@@ -911,20 +912,9 @@ int nvmap_alloc_handle_from_va(struct nvmap_client *client, | |||
911 | return err; | 912 | return err; |
912 | } | 913 | } |
913 | 914 | ||
914 | void _nvmap_handle_free(struct nvmap_handle *h) | 915 | void __nvmap_handle_free(struct nvmap_handle *h) |
915 | { | 916 | { |
916 | unsigned int i, nr_page, page_index = 0; | 917 | unsigned int i, nr_page, page_index = 0; |
917 | struct nvmap_handle_dmabuf_priv *curr, *next; | ||
918 | |||
919 | list_for_each_entry_safe(curr, next, &h->dmabuf_priv, list) { | ||
920 | curr->priv_release(curr->priv); | ||
921 | list_del(&curr->list); | ||
922 | kzfree(curr); | ||
923 | } | ||
924 | |||
925 | if (nvmap_handle_remove(nvmap_dev, h) != 0) | ||
926 | return; | ||
927 | |||
928 | if (!h->alloc) | 918 | if (!h->alloc) |
929 | goto out; | 919 | goto out; |
930 | 920 | ||
@@ -980,8 +970,24 @@ void _nvmap_handle_free(struct nvmap_handle *h) | |||
980 | } | 970 | } |
981 | 971 | ||
982 | nvmap_altfree(h->pgalloc.pages, nr_page * sizeof(struct page *)); | 972 | nvmap_altfree(h->pgalloc.pages, nr_page * sizeof(struct page *)); |
983 | |||
984 | out: | 973 | out: |
974 | h->alloc = false; | ||
975 | } | ||
976 | |||
977 | void _nvmap_handle_free(struct nvmap_handle *h) | ||
978 | { | ||
979 | struct nvmap_handle_dmabuf_priv *curr, *next; | ||
980 | |||
981 | list_for_each_entry_safe(curr, next, &h->dmabuf_priv, list) { | ||
982 | curr->priv_release(curr->priv); | ||
983 | list_del(&curr->list); | ||
984 | kzfree(curr); | ||
985 | } | ||
986 | |||
987 | if (nvmap_handle_remove(nvmap_dev, h) != 0) | ||
988 | return; | ||
989 | __nvmap_handle_free(h); | ||
990 | // Next two calls were originally in the `out` clause | ||
985 | NVMAP_TAG_TRACE(trace_nvmap_destroy_handle, | 991 | NVMAP_TAG_TRACE(trace_nvmap_destroy_handle, |
986 | NULL, get_current()->pid, 0, NVMAP_TP_ARGS_H(h)); | 992 | NULL, get_current()->pid, 0, NVMAP_TP_ARGS_H(h)); |
987 | kfree(h); | 993 | kfree(h); |
@@ -1041,3 +1047,57 @@ void nvmap_free_handle_fd(struct nvmap_client *client, | |||
1041 | nvmap_handle_put(handle); | 1047 | nvmap_handle_put(handle); |
1042 | } | 1048 | } |
1043 | } | 1049 | } |
1050 | |||
1051 | // Frees backing pages. Handle remains valid. | ||
1052 | void nvmap_dealloc_fd(struct nvmap_client *client, int fd) | ||
1053 | { | ||
1054 | struct nvmap_handle *handle = nvmap_handle_get_from_fd(fd); | ||
1055 | if (handle) | ||
1056 | __nvmap_handle_free(handle); | ||
1057 | } | ||
1058 | |||
1059 | // For deallocations from elsewhere in the kernel. | ||
1060 | // (Userspace should use NVMAP_IOC_DEALLOC ioctl.) | ||
1061 | int nvmap_dealloc_dmabuf(struct dma_buf *dmabuf) { | ||
1062 | struct nvmap_handle_info *info; | ||
1063 | |||
1064 | if (!dmabuf_is_nvmap(dmabuf)) | ||
1065 | return -EINVAL; | ||
1066 | info = dmabuf->priv; | ||
1067 | // Fail if mapped into kernelspace | ||
1068 | // (Unclear if this is necessary, but no handles have been observed with this | ||
1069 | // set, and so testing has not been possible.) | ||
1070 | if (atomic_read(&info->handle->kmap_count)) | ||
1071 | goto out_busy; | ||
1072 | // Buffer cannot currently be mapped into userspace (via mmap) | ||
1073 | if (atomic_read(&info->handle->umap_count)) | ||
1074 | goto out_busy; | ||
1075 | // Other devices should not still have this pinned into DMA memory | ||
1076 | if (atomic_read(&info->handle->pin)) | ||
1077 | goto out_busy; | ||
1078 | __nvmap_handle_free(info->handle); | ||
1079 | return 0; | ||
1080 | out_busy: | ||
1081 | printk(KERN_WARNING "nvmap: Unmap requested on FD that is currently in-use! (%d h->pin, %d h->kmap_count, %d h->umap_count)\n", | ||
1082 | atomic_read(&info->handle->pin), | ||
1083 | atomic_read(&info->handle->kmap_count), | ||
1084 | atomic_read(&info->handle->umap_count)); | ||
1085 | return -EBUSY; | ||
1086 | } | ||
1087 | EXPORT_SYMBOL(nvmap_dealloc_dmabuf); | ||
1088 | |||
1089 | // For reallocations from elsewhere in the kernel. | ||
1090 | // (Userspace should use NVMAP_IOC_ALLOC ioctl.) | ||
1091 | int nvmap_realloc_dmabuf(struct dma_buf *dmabuf) { | ||
1092 | struct nvmap_handle_info *info; | ||
1093 | struct nvmap_handle *h; | ||
1094 | |||
1095 | if (!dmabuf_is_nvmap(dmabuf)) | ||
1096 | return -EINVAL; | ||
1097 | info = dmabuf->priv; | ||
1098 | h = info->handle; | ||
1099 | return nvmap_alloc_handle(h->owner, h, h->userheap_mask, | ||
1100 | h->align, 0, h->userflags, | ||
1101 | NVMAP_IVM_INVALID_PEER); | ||
1102 | } | ||
1103 | EXPORT_SYMBOL(nvmap_realloc_dmabuf); | ||
diff --git a/drivers/video/tegra/nvmap/nvmap_dev.c b/drivers/video/tegra/nvmap/nvmap_dev.c index eb5791464..a11e3edfb 100644 --- a/drivers/video/tegra/nvmap/nvmap_dev.c +++ b/drivers/video/tegra/nvmap/nvmap_dev.c | |||
@@ -360,6 +360,10 @@ static long nvmap_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
360 | err = nvmap_ioctl_alloc(filp, uarg); | 360 | err = nvmap_ioctl_alloc(filp, uarg); |
361 | break; | 361 | break; |
362 | 362 | ||
363 | case NVMAP_IOC_DEALLOC: | ||
364 | err = nvmap_ioctl_dealloc(filp, arg); | ||
365 | break; | ||
366 | |||
363 | case NVMAP_IOC_ALLOC_IVM: | 367 | case NVMAP_IOC_ALLOC_IVM: |
364 | err = nvmap_ioctl_alloc_ivm(filp, uarg); | 368 | err = nvmap_ioctl_alloc_ivm(filp, uarg); |
365 | break; | 369 | break; |
diff --git a/drivers/video/tegra/nvmap/nvmap_dmabuf.c b/drivers/video/tegra/nvmap/nvmap_dmabuf.c index 850e07e06..33dcf5fe5 100644 --- a/drivers/video/tegra/nvmap/nvmap_dmabuf.c +++ b/drivers/video/tegra/nvmap/nvmap_dmabuf.c | |||
@@ -659,6 +659,7 @@ struct dma_buf *__nvmap_make_dmabuf(struct nvmap_client *client, | |||
659 | info->handle = handle; | 659 | info->handle = handle; |
660 | INIT_LIST_HEAD(&info->maps); | 660 | INIT_LIST_HEAD(&info->maps); |
661 | mutex_init(&info->maps_lock); | 661 | mutex_init(&info->maps_lock); |
662 | INIT_LIST_HEAD(&info->user_priv_list); | ||
662 | 663 | ||
663 | dmabuf = __dma_buf_export(info, handle->size, ro_buf); | 664 | dmabuf = __dma_buf_export(info, handle->size, ro_buf); |
664 | if (IS_ERR(dmabuf)) { | 665 | if (IS_ERR(dmabuf)) { |
@@ -791,3 +792,13 @@ error: | |||
791 | dma_buf_put(dmabuf); | 792 | dma_buf_put(dmabuf); |
792 | return ret; | 793 | return ret; |
793 | } | 794 | } |
795 | |||
796 | struct list_head* nvmap_get_priv_list(struct dma_buf *dmabuf) { | ||
797 | struct nvmap_handle_info *info; | ||
798 | |||
799 | if (!dmabuf_is_nvmap(dmabuf)) | ||
800 | return ERR_PTR(-EINVAL); | ||
801 | info = dmabuf->priv; | ||
802 | return &info->user_priv_list; | ||
803 | } | ||
804 | EXPORT_SYMBOL(nvmap_get_priv_list); | ||
diff --git a/drivers/video/tegra/nvmap/nvmap_ioctl.c b/drivers/video/tegra/nvmap/nvmap_ioctl.c index 7fd13e625..93a418eb3 100644 --- a/drivers/video/tegra/nvmap/nvmap_ioctl.c +++ b/drivers/video/tegra/nvmap/nvmap_ioctl.c | |||
@@ -460,6 +460,19 @@ int nvmap_ioctl_free(struct file *filp, unsigned long arg) | |||
460 | return sys_close(arg); | 460 | return sys_close(arg); |
461 | } | 461 | } |
462 | 462 | ||
463 | // Returns memory freed by deallocation | ||
464 | int nvmap_ioctl_dealloc(struct file *filp, unsigned long arg) | ||
465 | { | ||
466 | struct nvmap_client *client = filp->private_data; | ||
467 | u64 before = nvmap_stats_read(NS_TOTAL); | ||
468 | |||
469 | if (!arg) | ||
470 | return 0; | ||
471 | |||
472 | nvmap_dealloc_fd(client, arg); | ||
473 | return before - nvmap_stats_read(NS_TOTAL); | ||
474 | } | ||
475 | |||
463 | static ssize_t rw_handle(struct nvmap_client *client, struct nvmap_handle *h, | 476 | static ssize_t rw_handle(struct nvmap_client *client, struct nvmap_handle *h, |
464 | int is_read, unsigned long h_offs, | 477 | int is_read, unsigned long h_offs, |
465 | unsigned long sys_addr, unsigned long h_stride, | 478 | unsigned long sys_addr, unsigned long h_stride, |
diff --git a/drivers/video/tegra/nvmap/nvmap_ioctl.h b/drivers/video/tegra/nvmap/nvmap_ioctl.h index 6c64d2abe..f1b7b9e82 100644 --- a/drivers/video/tegra/nvmap/nvmap_ioctl.h +++ b/drivers/video/tegra/nvmap/nvmap_ioctl.h | |||
@@ -31,6 +31,8 @@ int nvmap_ioctl_getfd(struct file *filp, void __user *arg); | |||
31 | 31 | ||
32 | int nvmap_ioctl_alloc(struct file *filp, void __user *arg); | 32 | int nvmap_ioctl_alloc(struct file *filp, void __user *arg); |
33 | 33 | ||
34 | int nvmap_ioctl_dealloc(struct file *filp, unsigned long arg); | ||
35 | |||
34 | int nvmap_ioctl_alloc_kind(struct file *filp, void __user *arg); | 36 | int nvmap_ioctl_alloc_kind(struct file *filp, void __user *arg); |
35 | 37 | ||
36 | int nvmap_ioctl_alloc_ivm(struct file *filp, void __user *arg); | 38 | int nvmap_ioctl_alloc_ivm(struct file *filp, void __user *arg); |
diff --git a/drivers/video/tegra/nvmap/nvmap_priv.h b/drivers/video/tegra/nvmap/nvmap_priv.h index 781260b1d..9d668cd2e 100644 --- a/drivers/video/tegra/nvmap/nvmap_priv.h +++ b/drivers/video/tegra/nvmap/nvmap_priv.h | |||
@@ -174,6 +174,7 @@ struct nvmap_handle { | |||
174 | bool from_va; /* handle memory is from VA */ | 174 | bool from_va; /* handle memory is from VA */ |
175 | u32 heap_type; /* handle heap is allocated from */ | 175 | u32 heap_type; /* handle heap is allocated from */ |
176 | u32 userflags; /* flags passed from userspace */ | 176 | u32 userflags; /* flags passed from userspace */ |
177 | u32 userheap_mask; /* heap_mask passed from userspace */ | ||
177 | void *vaddr; /* mapping used inside kernel */ | 178 | void *vaddr; /* mapping used inside kernel */ |
178 | struct list_head vmas; /* list of all user vma's */ | 179 | struct list_head vmas; /* list of all user vma's */ |
179 | atomic_t umap_count; /* number of outstanding maps from user */ | 180 | atomic_t umap_count; /* number of outstanding maps from user */ |
@@ -191,6 +192,9 @@ struct nvmap_handle_info { | |||
191 | struct nvmap_handle *handle; | 192 | struct nvmap_handle *handle; |
192 | struct list_head maps; | 193 | struct list_head maps; |
193 | struct mutex maps_lock; | 194 | struct mutex maps_lock; |
195 | // Allow drivers such as nvgpu to optionally store pointers to their | ||
196 | // own internal state tracking structures | ||
197 | struct list_head user_priv_list; | ||
194 | }; | 198 | }; |
195 | 199 | ||
196 | struct nvmap_tag_entry { | 200 | struct nvmap_tag_entry { |
@@ -415,12 +419,16 @@ void nvmap_free_handle(struct nvmap_client *c, struct nvmap_handle *h); | |||
415 | 419 | ||
416 | void nvmap_free_handle_fd(struct nvmap_client *c, int fd); | 420 | void nvmap_free_handle_fd(struct nvmap_client *c, int fd); |
417 | 421 | ||
422 | void nvmap_dealloc_fd(struct nvmap_client *client, int fd); | ||
423 | |||
418 | int nvmap_handle_remove(struct nvmap_device *dev, struct nvmap_handle *h); | 424 | int nvmap_handle_remove(struct nvmap_device *dev, struct nvmap_handle *h); |
419 | 425 | ||
420 | void nvmap_handle_add(struct nvmap_device *dev, struct nvmap_handle *h); | 426 | void nvmap_handle_add(struct nvmap_device *dev, struct nvmap_handle *h); |
421 | 427 | ||
422 | int is_nvmap_vma(struct vm_area_struct *vma); | 428 | int is_nvmap_vma(struct vm_area_struct *vma); |
423 | 429 | ||
430 | bool dmabuf_is_nvmap(struct dma_buf *dmabuf); | ||
431 | |||
424 | int nvmap_get_dmabuf_fd(struct nvmap_client *client, struct nvmap_handle *h); | 432 | int nvmap_get_dmabuf_fd(struct nvmap_client *client, struct nvmap_handle *h); |
425 | struct nvmap_handle *nvmap_handle_get_from_dmabuf_fd( | 433 | struct nvmap_handle *nvmap_handle_get_from_dmabuf_fd( |
426 | struct nvmap_client *client, int fd); | 434 | struct nvmap_client *client, int fd); |