summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoshua Bakita <jbakita@cs.unc.edu>2022-05-24 21:16:30 -0400
committerJoshua Bakita <jbakita@cs.unc.edu>2022-05-24 21:16:30 -0400
commit2c076a01e5bd0949032ef81cd0e2d37bdecafba5 (patch)
tree12cc1d66b55a6a72ecdd40a416a86b117f04641a
parent70c252977fc080c829b195fece6f46f73586f1e4 (diff)
gpu-paging: Functions to support initial working versionrtss22-aegpu-paging
- Buffer deallocation (+IOCTL) - Buffer reallocation - Private dmabuf user list and accessor
-rw-r--r--drivers/video/tegra/nvmap/nvmap_alloc.c86
-rw-r--r--drivers/video/tegra/nvmap/nvmap_dev.c4
-rw-r--r--drivers/video/tegra/nvmap/nvmap_dmabuf.c11
-rw-r--r--drivers/video/tegra/nvmap/nvmap_ioctl.c13
-rw-r--r--drivers/video/tegra/nvmap/nvmap_ioctl.h2
-rw-r--r--drivers/video/tegra/nvmap/nvmap_priv.h8
-rw-r--r--include/linux/nvmap.h18
-rw-r--r--include/uapi/linux/nvmap.h2
8 files changed, 131 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
914void _nvmap_handle_free(struct nvmap_handle *h) 915void __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
984out: 973out:
974 h->alloc = false;
975}
976
977void _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.
1052void 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.)
1061int 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;
1080out_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}
1087EXPORT_SYMBOL(nvmap_dealloc_dmabuf);
1088
1089// For reallocations from elsewhere in the kernel.
1090// (Userspace should use NVMAP_IOC_ALLOC ioctl.)
1091int 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}
1103EXPORT_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
796struct 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}
804EXPORT_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
464int 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
463static ssize_t rw_handle(struct nvmap_client *client, struct nvmap_handle *h, 476static 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
32int nvmap_ioctl_alloc(struct file *filp, void __user *arg); 32int nvmap_ioctl_alloc(struct file *filp, void __user *arg);
33 33
34int nvmap_ioctl_dealloc(struct file *filp, unsigned long arg);
35
34int nvmap_ioctl_alloc_kind(struct file *filp, void __user *arg); 36int nvmap_ioctl_alloc_kind(struct file *filp, void __user *arg);
35 37
36int nvmap_ioctl_alloc_ivm(struct file *filp, void __user *arg); 38int 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
196struct nvmap_tag_entry { 200struct nvmap_tag_entry {
@@ -415,12 +419,16 @@ void nvmap_free_handle(struct nvmap_client *c, struct nvmap_handle *h);
415 419
416void nvmap_free_handle_fd(struct nvmap_client *c, int fd); 420void nvmap_free_handle_fd(struct nvmap_client *c, int fd);
417 421
422void nvmap_dealloc_fd(struct nvmap_client *client, int fd);
423
418int nvmap_handle_remove(struct nvmap_device *dev, struct nvmap_handle *h); 424int nvmap_handle_remove(struct nvmap_device *dev, struct nvmap_handle *h);
419 425
420void nvmap_handle_add(struct nvmap_device *dev, struct nvmap_handle *h); 426void nvmap_handle_add(struct nvmap_device *dev, struct nvmap_handle *h);
421 427
422int is_nvmap_vma(struct vm_area_struct *vma); 428int is_nvmap_vma(struct vm_area_struct *vma);
423 429
430bool dmabuf_is_nvmap(struct dma_buf *dmabuf);
431
424int nvmap_get_dmabuf_fd(struct nvmap_client *client, struct nvmap_handle *h); 432int nvmap_get_dmabuf_fd(struct nvmap_client *client, struct nvmap_handle *h);
425struct nvmap_handle *nvmap_handle_get_from_dmabuf_fd( 433struct nvmap_handle *nvmap_handle_get_from_dmabuf_fd(
426 struct nvmap_client *client, int fd); 434 struct nvmap_client *client, int fd);
diff --git a/include/linux/nvmap.h b/include/linux/nvmap.h
index b8d267691..7a8181ca5 100644
--- a/include/linux/nvmap.h
+++ b/include/linux/nvmap.h
@@ -65,6 +65,24 @@ ulong nvmap_iovmm_get_used_pages(void);
65int nvmap_register_vidmem_carveout(struct device *dma_dev, 65int nvmap_register_vidmem_carveout(struct device *dma_dev,
66 phys_addr_t base, size_t size); 66 phys_addr_t base, size_t size);
67 67
68/* The following two functions are to help enable DRAM
69 * overprovising via paging. These functions allow the
70 * physical frames backing an nvmap dma_buf to be freed
71 * (for example, after their contents has been saved
72 * elsewhere by paging logic), and to be reallocated
73 * (such as when other code is ready to repopulate them).
74 * Both functions preserve any open nvmap handles.
75 */
76int nvmap_dealloc_dmabuf(struct dma_buf *dmabuf);
77int nvmap_realloc_dmabuf(struct dma_buf *dmabuf);
78
79/* Some drivers (such as nvgpu) store parallel structures
80 * for each dmabuf to track internal state. To allow these
81 * drivers to quickly access their state from a *dmabuf or
82 * FD, we allow them access to a per-dmabuf list_head.
83 */
84struct list_head* nvmap_get_priv_list(struct dma_buf *dmabuf);
85
68/* 86/*
69 * A heap can be mapped to memory other than DRAM. 87 * A heap can be mapped to memory other than DRAM.
70 * The HW, controls the memory, can be power gated/ungated 88 * The HW, controls the memory, can be power gated/ungated
diff --git a/include/uapi/linux/nvmap.h b/include/uapi/linux/nvmap.h
index 66eda75ce..5fea19ac8 100644
--- a/include/uapi/linux/nvmap.h
+++ b/include/uapi/linux/nvmap.h
@@ -304,6 +304,8 @@ struct nvmap_handle_parameters {
304 */ 304 */
305#define NVMAP_IOC_FREE _IO(NVMAP_IOC_MAGIC, 4) 305#define NVMAP_IOC_FREE _IO(NVMAP_IOC_MAGIC, 4)
306 306
307#define NVMAP_IOC_DEALLOC _IO(NVMAP_IOC_MAGIC, 9)
308
307/* Maps the region of the specified handle into a user-provided virtual address 309/* Maps the region of the specified handle into a user-provided virtual address
308 * that was previously created via an mmap syscall on this fd */ 310 * that was previously created via an mmap syscall on this fd */
309#define NVMAP_IOC_MMAP _IOWR(NVMAP_IOC_MAGIC, 5, struct nvmap_map_caller) 311#define NVMAP_IOC_MMAP _IOWR(NVMAP_IOC_MAGIC, 5, struct nvmap_map_caller)