diff options
author | Alex Waterman <alexw@nvidia.com> | 2017-07-31 15:32:07 -0400 |
---|---|---|
committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2017-10-10 11:01:04 -0400 |
commit | 3c37701377459fbea2b460e1b9c65a863dfb04b2 (patch) | |
tree | 60a57a260dc8bcbd81089af8e9e966074e3bc881 | |
parent | b61306795b53647e8d1d4279417df1e1fe0f4b86 (diff) |
gpu: nvgpu: Split VIDMEM support from mm_gk20a.c
Split VIDMEM support into its own code files organized as such:
common/mm/vidmem.c - Base vidmem support
common/linux/vidmem.c - Linux specific user-space interaction
include/nvgpu/vidmem.h - Vidmem API definitions
Also use the config to enable/disable VIDMEM support in the makefile
and remove as many CONFIG_GK20A_VIDMEM preprocessor checks as possible
from the source code.
And lastly update a while-loop that iterated over an SGT to use the
new for_each construct for iterating over SGTs.
Currently this organization is not perfectly adhered to. More patches
will fix that.
JIRA NVGPU-30
JIRA NVGPU-138
Change-Id: Ic0f4d2cf38b65849c7dc350a69b175421477069c
Signed-off-by: Alex Waterman <alexw@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1540705
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
-rw-r--r-- | drivers/gpu/nvgpu/Makefile.nvgpu | 4 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/dma.c | 1 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c | 1 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/nvgpu_mem.c | 1 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/vidmem.c | 268 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/vm.c | 29 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/mm/gmmu.c | 1 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/mm/nvgpu_mem.c | 1 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/mm/vidmem.c | 259 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/pramin.c | 1 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c | 1 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/mm_gk20a.c | 541 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/mm_gk20a.h | 9 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/include/nvgpu/vidmem.h | 139 |
14 files changed, 707 insertions, 549 deletions
diff --git a/drivers/gpu/nvgpu/Makefile.nvgpu b/drivers/gpu/nvgpu/Makefile.nvgpu index 35d5109b..a792ab33 100644 --- a/drivers/gpu/nvgpu/Makefile.nvgpu +++ b/drivers/gpu/nvgpu/Makefile.nvgpu | |||
@@ -121,6 +121,10 @@ nvgpu-y := \ | |||
121 | boardobj/boardobjgrp_e255.o \ | 121 | boardobj/boardobjgrp_e255.o \ |
122 | boardobj/boardobjgrp_e32.o | 122 | boardobj/boardobjgrp_e32.o |
123 | 123 | ||
124 | nvgpu-$(CONFIG_GK20A_VIDMEM) += \ | ||
125 | common/mm/vidmem.o \ | ||
126 | common/linux/vidmem.o | ||
127 | |||
124 | nvgpu-$(CONFIG_DEBUG_FS) += \ | 128 | nvgpu-$(CONFIG_DEBUG_FS) += \ |
125 | common/linux/debug.o \ | 129 | common/linux/debug.o \ |
126 | common/linux/debug_gr.o \ | 130 | common/linux/debug_gr.o \ |
diff --git a/drivers/gpu/nvgpu/common/linux/dma.c b/drivers/gpu/nvgpu/common/linux/dma.c index 7b892731..2ed1cc5a 100644 --- a/drivers/gpu/nvgpu/common/linux/dma.c +++ b/drivers/gpu/nvgpu/common/linux/dma.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <nvgpu/gmmu.h> | 25 | #include <nvgpu/gmmu.h> |
26 | #include <nvgpu/kmem.h> | 26 | #include <nvgpu/kmem.h> |
27 | #include <nvgpu/enabled.h> | 27 | #include <nvgpu/enabled.h> |
28 | #include <nvgpu/vidmem.h> | ||
28 | 29 | ||
29 | #include <nvgpu/linux/dma.h> | 30 | #include <nvgpu/linux/dma.h> |
30 | 31 | ||
diff --git a/drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c b/drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c index 220cb3e7..87ae0a3d 100644 --- a/drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c +++ b/drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <nvgpu/kmem.h> | 25 | #include <nvgpu/kmem.h> |
26 | #include <nvgpu/bug.h> | 26 | #include <nvgpu/bug.h> |
27 | #include <nvgpu/bus.h> | 27 | #include <nvgpu/bus.h> |
28 | #include <nvgpu/vidmem.h> | ||
28 | 29 | ||
29 | #include "ioctl_ctrl.h" | 30 | #include "ioctl_ctrl.h" |
30 | #include "ioctl_tsg.h" | 31 | #include "ioctl_tsg.h" |
diff --git a/drivers/gpu/nvgpu/common/linux/nvgpu_mem.c b/drivers/gpu/nvgpu/common/linux/nvgpu_mem.c index 0be41a44..e8aea0be 100644 --- a/drivers/gpu/nvgpu/common/linux/nvgpu_mem.c +++ b/drivers/gpu/nvgpu/common/linux/nvgpu_mem.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <nvgpu/bug.h> | 22 | #include <nvgpu/bug.h> |
23 | #include <nvgpu/enabled.h> | 23 | #include <nvgpu/enabled.h> |
24 | #include <nvgpu/kmem.h> | 24 | #include <nvgpu/kmem.h> |
25 | #include <nvgpu/vidmem.h> | ||
25 | 26 | ||
26 | #include <nvgpu/linux/dma.h> | 27 | #include <nvgpu/linux/dma.h> |
27 | 28 | ||
diff --git a/drivers/gpu/nvgpu/common/linux/vidmem.c b/drivers/gpu/nvgpu/common/linux/vidmem.c new file mode 100644 index 00000000..e89dd07a --- /dev/null +++ b/drivers/gpu/nvgpu/common/linux/vidmem.c | |||
@@ -0,0 +1,268 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2017, 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 <linux/dma-buf.h> | ||
18 | |||
19 | #include <linux/platform/tegra/tegra_fd.h> | ||
20 | |||
21 | #include <nvgpu/dma.h> | ||
22 | #include <nvgpu/enabled.h> | ||
23 | #include <nvgpu/vidmem.h> | ||
24 | #include <nvgpu/nvgpu_mem.h> | ||
25 | #include <nvgpu/page_allocator.h> | ||
26 | |||
27 | #include <nvgpu/linux/dma.h> | ||
28 | |||
29 | #include "gk20a/gk20a.h" | ||
30 | #include "gk20a/mm_gk20a.h" | ||
31 | |||
32 | #include "vm_priv.h" | ||
33 | |||
34 | void set_vidmem_page_alloc(struct scatterlist *sgl, u64 addr) | ||
35 | { | ||
36 | /* set bit 0 to indicate vidmem allocation */ | ||
37 | sg_dma_address(sgl) = (addr | 1ULL); | ||
38 | } | ||
39 | |||
40 | bool is_vidmem_page_alloc(u64 addr) | ||
41 | { | ||
42 | return !!(addr & 1ULL); | ||
43 | } | ||
44 | |||
45 | struct nvgpu_page_alloc *get_vidmem_page_alloc(struct scatterlist *sgl) | ||
46 | { | ||
47 | u64 addr; | ||
48 | |||
49 | addr = sg_dma_address(sgl); | ||
50 | |||
51 | if (is_vidmem_page_alloc(addr)) | ||
52 | addr = addr & ~1ULL; | ||
53 | else | ||
54 | WARN_ON(1); | ||
55 | |||
56 | return (struct nvgpu_page_alloc *)(uintptr_t)addr; | ||
57 | } | ||
58 | |||
59 | static struct sg_table *gk20a_vidbuf_map_dma_buf( | ||
60 | struct dma_buf_attachment *attach, enum dma_data_direction dir) | ||
61 | { | ||
62 | struct gk20a_vidmem_buf *buf = attach->dmabuf->priv; | ||
63 | |||
64 | return buf->mem->priv.sgt; | ||
65 | } | ||
66 | |||
67 | static void gk20a_vidbuf_unmap_dma_buf(struct dma_buf_attachment *attach, | ||
68 | struct sg_table *sgt, | ||
69 | enum dma_data_direction dir) | ||
70 | { | ||
71 | } | ||
72 | |||
73 | static void gk20a_vidbuf_release(struct dma_buf *dmabuf) | ||
74 | { | ||
75 | struct gk20a_vidmem_buf *buf = dmabuf->priv; | ||
76 | |||
77 | gk20a_dbg_fn(""); | ||
78 | |||
79 | if (buf->dmabuf_priv) | ||
80 | buf->dmabuf_priv_delete(buf->dmabuf_priv); | ||
81 | |||
82 | nvgpu_dma_free(buf->g, buf->mem); | ||
83 | nvgpu_kfree(buf->g, buf); | ||
84 | } | ||
85 | |||
86 | static void *gk20a_vidbuf_kmap(struct dma_buf *dmabuf, unsigned long page_num) | ||
87 | { | ||
88 | WARN_ON("Not supported"); | ||
89 | return NULL; | ||
90 | } | ||
91 | |||
92 | static void *gk20a_vidbuf_kmap_atomic(struct dma_buf *dmabuf, | ||
93 | unsigned long page_num) | ||
94 | { | ||
95 | WARN_ON("Not supported"); | ||
96 | return NULL; | ||
97 | } | ||
98 | |||
99 | static int gk20a_vidbuf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) | ||
100 | { | ||
101 | return -EINVAL; | ||
102 | } | ||
103 | |||
104 | static int gk20a_vidbuf_set_private(struct dma_buf *dmabuf, | ||
105 | struct device *dev, void *priv, void (*delete)(void *priv)) | ||
106 | { | ||
107 | struct gk20a_vidmem_buf *buf = dmabuf->priv; | ||
108 | |||
109 | buf->dmabuf_priv = priv; | ||
110 | buf->dmabuf_priv_delete = delete; | ||
111 | |||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static void *gk20a_vidbuf_get_private(struct dma_buf *dmabuf, | ||
116 | struct device *dev) | ||
117 | { | ||
118 | struct gk20a_vidmem_buf *buf = dmabuf->priv; | ||
119 | |||
120 | return buf->dmabuf_priv; | ||
121 | } | ||
122 | |||
123 | static const struct dma_buf_ops gk20a_vidbuf_ops = { | ||
124 | .map_dma_buf = gk20a_vidbuf_map_dma_buf, | ||
125 | .unmap_dma_buf = gk20a_vidbuf_unmap_dma_buf, | ||
126 | .release = gk20a_vidbuf_release, | ||
127 | .kmap_atomic = gk20a_vidbuf_kmap_atomic, | ||
128 | .kmap = gk20a_vidbuf_kmap, | ||
129 | .mmap = gk20a_vidbuf_mmap, | ||
130 | .set_drvdata = gk20a_vidbuf_set_private, | ||
131 | .get_drvdata = gk20a_vidbuf_get_private, | ||
132 | }; | ||
133 | |||
134 | static struct dma_buf *gk20a_vidbuf_export(struct gk20a_vidmem_buf *buf) | ||
135 | { | ||
136 | DEFINE_DMA_BUF_EXPORT_INFO(exp_info); | ||
137 | |||
138 | exp_info.priv = buf; | ||
139 | exp_info.ops = &gk20a_vidbuf_ops; | ||
140 | exp_info.size = buf->mem->size; | ||
141 | exp_info.flags = O_RDWR; | ||
142 | |||
143 | return dma_buf_export(&exp_info); | ||
144 | } | ||
145 | |||
146 | struct gk20a *gk20a_vidmem_buf_owner(struct dma_buf *dmabuf) | ||
147 | { | ||
148 | struct gk20a_vidmem_buf *buf = dmabuf->priv; | ||
149 | |||
150 | if (dmabuf->ops != &gk20a_vidbuf_ops) | ||
151 | return NULL; | ||
152 | |||
153 | return buf->g; | ||
154 | } | ||
155 | |||
156 | int gk20a_vidmem_buf_alloc(struct gk20a *g, size_t bytes) | ||
157 | { | ||
158 | struct gk20a_vidmem_buf *buf; | ||
159 | int err = 0, fd; | ||
160 | |||
161 | gk20a_dbg_fn(""); | ||
162 | |||
163 | buf = nvgpu_kzalloc(g, sizeof(*buf)); | ||
164 | if (!buf) | ||
165 | return -ENOMEM; | ||
166 | |||
167 | buf->g = g; | ||
168 | |||
169 | if (!g->mm.vidmem.cleared) { | ||
170 | nvgpu_mutex_acquire(&g->mm.vidmem.first_clear_mutex); | ||
171 | if (!g->mm.vidmem.cleared) { | ||
172 | err = gk20a_vidmem_clear_all(g); | ||
173 | if (err) { | ||
174 | nvgpu_err(g, | ||
175 | "failed to clear whole vidmem"); | ||
176 | goto err_kfree; | ||
177 | } | ||
178 | } | ||
179 | nvgpu_mutex_release(&g->mm.vidmem.first_clear_mutex); | ||
180 | } | ||
181 | |||
182 | buf->mem = nvgpu_kzalloc(g, sizeof(struct nvgpu_mem)); | ||
183 | if (!buf->mem) | ||
184 | goto err_kfree; | ||
185 | |||
186 | buf->mem->mem_flags |= NVGPU_MEM_FLAG_USER_MEM; | ||
187 | |||
188 | err = nvgpu_dma_alloc_vid(g, bytes, buf->mem); | ||
189 | if (err) | ||
190 | goto err_memfree; | ||
191 | |||
192 | buf->dmabuf = gk20a_vidbuf_export(buf); | ||
193 | if (IS_ERR(buf->dmabuf)) { | ||
194 | err = PTR_ERR(buf->dmabuf); | ||
195 | goto err_bfree; | ||
196 | } | ||
197 | |||
198 | fd = tegra_alloc_fd(current->files, 1024, O_RDWR); | ||
199 | if (fd < 0) { | ||
200 | /* ->release frees what we have done */ | ||
201 | dma_buf_put(buf->dmabuf); | ||
202 | return fd; | ||
203 | } | ||
204 | |||
205 | /* fclose() on this drops one ref, freeing the dma buf */ | ||
206 | fd_install(fd, buf->dmabuf->file); | ||
207 | |||
208 | return fd; | ||
209 | |||
210 | err_bfree: | ||
211 | nvgpu_dma_free(g, buf->mem); | ||
212 | err_memfree: | ||
213 | nvgpu_kfree(g, buf->mem); | ||
214 | err_kfree: | ||
215 | nvgpu_kfree(g, buf); | ||
216 | return err; | ||
217 | } | ||
218 | |||
219 | int gk20a_vidbuf_access_memory(struct gk20a *g, struct dma_buf *dmabuf, | ||
220 | void *buffer, u64 offset, u64 size, u32 cmd) | ||
221 | { | ||
222 | struct gk20a_vidmem_buf *vidmem_buf; | ||
223 | struct nvgpu_mem *mem; | ||
224 | int err = 0; | ||
225 | |||
226 | if (gk20a_dmabuf_aperture(g, dmabuf) != APERTURE_VIDMEM) | ||
227 | return -EINVAL; | ||
228 | |||
229 | vidmem_buf = dmabuf->priv; | ||
230 | mem = vidmem_buf->mem; | ||
231 | |||
232 | switch (cmd) { | ||
233 | case NVGPU_DBG_GPU_IOCTL_ACCESS_FB_MEMORY_CMD_READ: | ||
234 | nvgpu_mem_rd_n(g, mem, offset, buffer, size); | ||
235 | break; | ||
236 | |||
237 | case NVGPU_DBG_GPU_IOCTL_ACCESS_FB_MEMORY_CMD_WRITE: | ||
238 | nvgpu_mem_wr_n(g, mem, offset, buffer, size); | ||
239 | break; | ||
240 | |||
241 | default: | ||
242 | err = -EINVAL; | ||
243 | } | ||
244 | |||
245 | return err; | ||
246 | } | ||
247 | |||
248 | void gk20a_vidmem_clear_mem_worker(struct work_struct *work) | ||
249 | { | ||
250 | struct mm_gk20a *mm = container_of(work, struct mm_gk20a, | ||
251 | vidmem.clear_mem_worker); | ||
252 | struct gk20a *g = mm->g; | ||
253 | struct nvgpu_mem *mem; | ||
254 | |||
255 | while ((mem = get_pending_mem_desc(mm)) != NULL) { | ||
256 | gk20a_gmmu_clear_vidmem_mem(g, mem); | ||
257 | nvgpu_free(mem->allocator, | ||
258 | (u64)get_vidmem_page_alloc(mem->priv.sgt->sgl)); | ||
259 | nvgpu_free_sgtable(g, &mem->priv.sgt); | ||
260 | |||
261 | WARN_ON(nvgpu_atomic64_sub_return(mem->aligned_size, | ||
262 | &g->mm.vidmem.bytes_pending) < 0); | ||
263 | mem->size = 0; | ||
264 | mem->aperture = APERTURE_INVALID; | ||
265 | |||
266 | nvgpu_kfree(g, mem); | ||
267 | } | ||
268 | } | ||
diff --git a/drivers/gpu/nvgpu/common/linux/vm.c b/drivers/gpu/nvgpu/common/linux/vm.c index 2e29f0f7..f4ac3d41 100644 --- a/drivers/gpu/nvgpu/common/linux/vm.c +++ b/drivers/gpu/nvgpu/common/linux/vm.c | |||
@@ -23,6 +23,8 @@ | |||
23 | #include <nvgpu/vm_area.h> | 23 | #include <nvgpu/vm_area.h> |
24 | #include <nvgpu/nvgpu_mem.h> | 24 | #include <nvgpu/nvgpu_mem.h> |
25 | #include <nvgpu/page_allocator.h> | 25 | #include <nvgpu/page_allocator.h> |
26 | #include <nvgpu/vidmem.h> | ||
27 | #include <nvgpu/enabled.h> | ||
26 | 28 | ||
27 | #include <nvgpu/linux/nvgpu_mem.h> | 29 | #include <nvgpu/linux/nvgpu_mem.h> |
28 | 30 | ||
@@ -34,6 +36,33 @@ | |||
34 | #include "vm_priv.h" | 36 | #include "vm_priv.h" |
35 | #include "os_linux.h" | 37 | #include "os_linux.h" |
36 | 38 | ||
39 | /* | ||
40 | * Temporary location for this code until a dmabuf.c file exists. | ||
41 | */ | ||
42 | enum nvgpu_aperture gk20a_dmabuf_aperture(struct gk20a *g, | ||
43 | struct dma_buf *dmabuf) | ||
44 | { | ||
45 | struct gk20a *buf_owner = gk20a_vidmem_buf_owner(dmabuf); | ||
46 | bool unified_memory = nvgpu_is_enabled(g, NVGPU_MM_UNIFIED_MEMORY); | ||
47 | |||
48 | if (buf_owner == NULL) { | ||
49 | /* Not nvgpu-allocated, assume system memory */ | ||
50 | return APERTURE_SYSMEM; | ||
51 | } else if (WARN_ON(buf_owner == g && unified_memory)) { | ||
52 | /* Looks like our video memory, but this gpu doesn't support | ||
53 | * it. Warn about a bug and bail out */ | ||
54 | nvgpu_warn(g, | ||
55 | "dmabuf is our vidmem but we don't have local vidmem"); | ||
56 | return APERTURE_INVALID; | ||
57 | } else if (buf_owner != g) { | ||
58 | /* Someone else's vidmem */ | ||
59 | return APERTURE_INVALID; | ||
60 | } else { | ||
61 | /* Yay, buf_owner == g */ | ||
62 | return APERTURE_VIDMEM; | ||
63 | } | ||
64 | } | ||
65 | |||
37 | static struct nvgpu_mapped_buf *__nvgpu_vm_find_mapped_buf_reverse( | 66 | static struct nvgpu_mapped_buf *__nvgpu_vm_find_mapped_buf_reverse( |
38 | struct vm_gk20a *vm, struct dma_buf *dmabuf, u32 kind) | 67 | struct vm_gk20a *vm, struct dma_buf *dmabuf, u32 kind) |
39 | { | 68 | { |
diff --git a/drivers/gpu/nvgpu/common/mm/gmmu.c b/drivers/gpu/nvgpu/common/mm/gmmu.c index f61ec3fc..1eed3a3b 100644 --- a/drivers/gpu/nvgpu/common/mm/gmmu.c +++ b/drivers/gpu/nvgpu/common/mm/gmmu.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <nvgpu/enabled.h> | 28 | #include <nvgpu/enabled.h> |
29 | #include <nvgpu/page_allocator.h> | 29 | #include <nvgpu/page_allocator.h> |
30 | #include <nvgpu/barrier.h> | 30 | #include <nvgpu/barrier.h> |
31 | #include <nvgpu/vidmem.h> | ||
31 | 32 | ||
32 | #include "gk20a/gk20a.h" | 33 | #include "gk20a/gk20a.h" |
33 | #include "gk20a/mm_gk20a.h" | 34 | #include "gk20a/mm_gk20a.h" |
diff --git a/drivers/gpu/nvgpu/common/mm/nvgpu_mem.c b/drivers/gpu/nvgpu/common/mm/nvgpu_mem.c index faee482d..2b6e6e6a 100644 --- a/drivers/gpu/nvgpu/common/mm/nvgpu_mem.c +++ b/drivers/gpu/nvgpu/common/mm/nvgpu_mem.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <nvgpu/kmem.h> | 23 | #include <nvgpu/kmem.h> |
24 | #include <nvgpu/nvgpu_mem.h> | 24 | #include <nvgpu/nvgpu_mem.h> |
25 | #include <nvgpu/dma.h> | 25 | #include <nvgpu/dma.h> |
26 | #include <nvgpu/vidmem.h> | ||
26 | 27 | ||
27 | #include "gk20a/gk20a.h" | 28 | #include "gk20a/gk20a.h" |
28 | 29 | ||
diff --git a/drivers/gpu/nvgpu/common/mm/vidmem.c b/drivers/gpu/nvgpu/common/mm/vidmem.c new file mode 100644 index 00000000..1ba07ca6 --- /dev/null +++ b/drivers/gpu/nvgpu/common/mm/vidmem.c | |||
@@ -0,0 +1,259 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | * DEALINGS IN THE SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #include <linux/scatterlist.h> | ||
24 | |||
25 | #include <nvgpu/vidmem.h> | ||
26 | #include <nvgpu/page_allocator.h> | ||
27 | |||
28 | #include "gk20a/gk20a.h" | ||
29 | #include "gk20a/mm_gk20a.h" | ||
30 | |||
31 | void gk20a_vidmem_destroy(struct gk20a *g) | ||
32 | { | ||
33 | if (nvgpu_alloc_initialized(&g->mm.vidmem.allocator)) | ||
34 | nvgpu_alloc_destroy(&g->mm.vidmem.allocator); | ||
35 | } | ||
36 | |||
37 | int gk20a_vidmem_clear_all(struct gk20a *g) | ||
38 | { | ||
39 | struct mm_gk20a *mm = &g->mm; | ||
40 | struct gk20a_fence *gk20a_fence_out = NULL; | ||
41 | u64 region2_base = 0; | ||
42 | int err = 0; | ||
43 | |||
44 | if (mm->vidmem.ce_ctx_id == (u32)~0) | ||
45 | return -EINVAL; | ||
46 | |||
47 | err = gk20a_ce_execute_ops(g, | ||
48 | mm->vidmem.ce_ctx_id, | ||
49 | 0, | ||
50 | mm->vidmem.base, | ||
51 | mm->vidmem.bootstrap_base - mm->vidmem.base, | ||
52 | 0x00000000, | ||
53 | NVGPU_CE_DST_LOCATION_LOCAL_FB, | ||
54 | NVGPU_CE_MEMSET, | ||
55 | NULL, | ||
56 | 0, | ||
57 | NULL); | ||
58 | if (err) { | ||
59 | nvgpu_err(g, | ||
60 | "Failed to clear vidmem region 1 : %d", err); | ||
61 | return err; | ||
62 | } | ||
63 | |||
64 | region2_base = mm->vidmem.bootstrap_base + mm->vidmem.bootstrap_size; | ||
65 | |||
66 | err = gk20a_ce_execute_ops(g, | ||
67 | mm->vidmem.ce_ctx_id, | ||
68 | 0, | ||
69 | region2_base, | ||
70 | mm->vidmem.size - region2_base, | ||
71 | 0x00000000, | ||
72 | NVGPU_CE_DST_LOCATION_LOCAL_FB, | ||
73 | NVGPU_CE_MEMSET, | ||
74 | NULL, | ||
75 | 0, | ||
76 | &gk20a_fence_out); | ||
77 | if (err) { | ||
78 | nvgpu_err(g, | ||
79 | "Failed to clear vidmem region 2 : %d", err); | ||
80 | return err; | ||
81 | } | ||
82 | |||
83 | if (gk20a_fence_out) { | ||
84 | struct nvgpu_timeout timeout; | ||
85 | |||
86 | nvgpu_timeout_init(g, &timeout, | ||
87 | gk20a_get_gr_idle_timeout(g), | ||
88 | NVGPU_TIMER_CPU_TIMER); | ||
89 | |||
90 | do { | ||
91 | err = gk20a_fence_wait(g, gk20a_fence_out, | ||
92 | gk20a_get_gr_idle_timeout(g)); | ||
93 | } while (err == -ERESTARTSYS && | ||
94 | !nvgpu_timeout_expired(&timeout)); | ||
95 | |||
96 | gk20a_fence_put(gk20a_fence_out); | ||
97 | if (err) { | ||
98 | nvgpu_err(g, | ||
99 | "fence wait failed for CE execute ops"); | ||
100 | return err; | ||
101 | } | ||
102 | } | ||
103 | |||
104 | mm->vidmem.cleared = true; | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | int gk20a_init_vidmem(struct mm_gk20a *mm) | ||
110 | { | ||
111 | struct gk20a *g = mm->g; | ||
112 | size_t size = g->ops.mm.get_vidmem_size ? | ||
113 | g->ops.mm.get_vidmem_size(g) : 0; | ||
114 | u64 bootstrap_base, bootstrap_size, base; | ||
115 | u64 default_page_size = SZ_64K; | ||
116 | int err; | ||
117 | |||
118 | static struct nvgpu_alloc_carveout wpr_co = | ||
119 | NVGPU_CARVEOUT("wpr-region", 0, SZ_16M); | ||
120 | |||
121 | if (!size) | ||
122 | return 0; | ||
123 | |||
124 | wpr_co.base = size - SZ_256M; | ||
125 | bootstrap_base = wpr_co.base; | ||
126 | bootstrap_size = SZ_16M; | ||
127 | base = default_page_size; | ||
128 | |||
129 | /* | ||
130 | * Bootstrap allocator for use before the CE is initialized (CE | ||
131 | * initialization requires vidmem but we want to use the CE to zero | ||
132 | * out vidmem before allocating it... | ||
133 | */ | ||
134 | err = nvgpu_page_allocator_init(g, &g->mm.vidmem.bootstrap_allocator, | ||
135 | "vidmem-bootstrap", | ||
136 | bootstrap_base, bootstrap_size, | ||
137 | SZ_4K, 0); | ||
138 | |||
139 | err = nvgpu_page_allocator_init(g, &g->mm.vidmem.allocator, | ||
140 | "vidmem", | ||
141 | base, size - base, | ||
142 | default_page_size, | ||
143 | GPU_ALLOC_4K_VIDMEM_PAGES); | ||
144 | if (err) { | ||
145 | nvgpu_err(g, "Failed to register vidmem for size %zu: %d", | ||
146 | size, err); | ||
147 | return err; | ||
148 | } | ||
149 | |||
150 | /* Reserve bootstrap region in vidmem allocator */ | ||
151 | nvgpu_alloc_reserve_carveout(&g->mm.vidmem.allocator, &wpr_co); | ||
152 | |||
153 | mm->vidmem.base = base; | ||
154 | mm->vidmem.size = size - base; | ||
155 | mm->vidmem.bootstrap_base = bootstrap_base; | ||
156 | mm->vidmem.bootstrap_size = bootstrap_size; | ||
157 | |||
158 | nvgpu_mutex_init(&mm->vidmem.first_clear_mutex); | ||
159 | |||
160 | INIT_WORK(&mm->vidmem.clear_mem_worker, gk20a_vidmem_clear_mem_worker); | ||
161 | nvgpu_atomic64_set(&mm->vidmem.bytes_pending, 0); | ||
162 | nvgpu_init_list_node(&mm->vidmem.clear_list_head); | ||
163 | nvgpu_mutex_init(&mm->vidmem.clear_list_mutex); | ||
164 | |||
165 | gk20a_dbg_info("registered vidmem: %zu MB", size / SZ_1M); | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | int gk20a_vidmem_get_space(struct gk20a *g, u64 *space) | ||
171 | { | ||
172 | struct nvgpu_allocator *allocator = &g->mm.vidmem.allocator; | ||
173 | |||
174 | gk20a_dbg_fn(""); | ||
175 | |||
176 | if (!nvgpu_alloc_initialized(allocator)) | ||
177 | return -ENOSYS; | ||
178 | |||
179 | nvgpu_mutex_acquire(&g->mm.vidmem.clear_list_mutex); | ||
180 | *space = nvgpu_alloc_space(allocator) + | ||
181 | nvgpu_atomic64_read(&g->mm.vidmem.bytes_pending); | ||
182 | nvgpu_mutex_release(&g->mm.vidmem.clear_list_mutex); | ||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | int gk20a_gmmu_clear_vidmem_mem(struct gk20a *g, struct nvgpu_mem *mem) | ||
187 | { | ||
188 | struct gk20a_fence *gk20a_fence_out = NULL; | ||
189 | struct gk20a_fence *gk20a_last_fence = NULL; | ||
190 | struct nvgpu_page_alloc *alloc = NULL; | ||
191 | void *sgl = NULL; | ||
192 | int err = 0; | ||
193 | |||
194 | if (g->mm.vidmem.ce_ctx_id == (u32)~0) | ||
195 | return -EINVAL; | ||
196 | |||
197 | alloc = get_vidmem_page_alloc(mem->priv.sgt->sgl); | ||
198 | |||
199 | nvgpu_sgt_for_each_sgl(sgl, &alloc->sgt) { | ||
200 | if (gk20a_last_fence) | ||
201 | gk20a_fence_put(gk20a_last_fence); | ||
202 | |||
203 | err = gk20a_ce_execute_ops(g, | ||
204 | g->mm.vidmem.ce_ctx_id, | ||
205 | 0, | ||
206 | nvgpu_sgt_get_phys(&alloc->sgt, sgl), | ||
207 | nvgpu_sgt_get_length(&alloc->sgt, sgl), | ||
208 | 0x00000000, | ||
209 | NVGPU_CE_DST_LOCATION_LOCAL_FB, | ||
210 | NVGPU_CE_MEMSET, | ||
211 | NULL, | ||
212 | 0, | ||
213 | &gk20a_fence_out); | ||
214 | |||
215 | if (err) { | ||
216 | nvgpu_err(g, | ||
217 | "Failed gk20a_ce_execute_ops[%d]", err); | ||
218 | return err; | ||
219 | } | ||
220 | |||
221 | gk20a_last_fence = gk20a_fence_out; | ||
222 | } | ||
223 | |||
224 | if (gk20a_last_fence) { | ||
225 | struct nvgpu_timeout timeout; | ||
226 | |||
227 | nvgpu_timeout_init(g, &timeout, | ||
228 | gk20a_get_gr_idle_timeout(g), | ||
229 | NVGPU_TIMER_CPU_TIMER); | ||
230 | |||
231 | do { | ||
232 | err = gk20a_fence_wait(g, gk20a_last_fence, | ||
233 | gk20a_get_gr_idle_timeout(g)); | ||
234 | } while (err == -ERESTARTSYS && | ||
235 | !nvgpu_timeout_expired(&timeout)); | ||
236 | |||
237 | gk20a_fence_put(gk20a_last_fence); | ||
238 | if (err) | ||
239 | nvgpu_err(g, | ||
240 | "fence wait failed for CE execute ops"); | ||
241 | } | ||
242 | |||
243 | return err; | ||
244 | } | ||
245 | |||
246 | struct nvgpu_mem *get_pending_mem_desc(struct mm_gk20a *mm) | ||
247 | { | ||
248 | struct nvgpu_mem *mem = NULL; | ||
249 | |||
250 | nvgpu_mutex_acquire(&mm->vidmem.clear_list_mutex); | ||
251 | if (!nvgpu_list_empty(&mm->vidmem.clear_list_head)) { | ||
252 | mem = nvgpu_list_first_entry(&mm->vidmem.clear_list_head, | ||
253 | nvgpu_mem, clear_list_entry); | ||
254 | nvgpu_list_del(&mem->clear_list_entry); | ||
255 | } | ||
256 | nvgpu_mutex_release(&mm->vidmem.clear_list_mutex); | ||
257 | |||
258 | return mem; | ||
259 | } | ||
diff --git a/drivers/gpu/nvgpu/common/pramin.c b/drivers/gpu/nvgpu/common/pramin.c index 4f7d6248..56179a6b 100644 --- a/drivers/gpu/nvgpu/common/pramin.c +++ b/drivers/gpu/nvgpu/common/pramin.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <nvgpu/pramin.h> | 23 | #include <nvgpu/pramin.h> |
24 | #include <nvgpu/page_allocator.h> | 24 | #include <nvgpu/page_allocator.h> |
25 | #include <nvgpu/enabled.h> | 25 | #include <nvgpu/enabled.h> |
26 | #include <nvgpu/vidmem.h> | ||
26 | 27 | ||
27 | #include "gk20a/gk20a.h" | 28 | #include "gk20a/gk20a.h" |
28 | 29 | ||
diff --git a/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c b/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c index e352c01f..d1eff233 100644 --- a/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <nvgpu/log.h> | 33 | #include <nvgpu/log.h> |
34 | #include <nvgpu/vm.h> | 34 | #include <nvgpu/vm.h> |
35 | #include <nvgpu/atomic.h> | 35 | #include <nvgpu/atomic.h> |
36 | #include <nvgpu/vidmem.h> | ||
36 | 37 | ||
37 | #include "gk20a.h" | 38 | #include "gk20a.h" |
38 | #include "gk20a/platform_gk20a.h" | 39 | #include "gk20a/platform_gk20a.h" |
diff --git a/drivers/gpu/nvgpu/gk20a/mm_gk20a.c b/drivers/gpu/nvgpu/gk20a/mm_gk20a.c index 795f7bda..c6ea2587 100644 --- a/drivers/gpu/nvgpu/gk20a/mm_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/mm_gk20a.c | |||
@@ -27,7 +27,6 @@ | |||
27 | #include <linux/dma-mapping.h> | 27 | #include <linux/dma-mapping.h> |
28 | #include <linux/dma-attrs.h> | 28 | #include <linux/dma-attrs.h> |
29 | #include <linux/lcm.h> | 29 | #include <linux/lcm.h> |
30 | #include <linux/platform/tegra/tegra_fd.h> | ||
31 | #include <uapi/linux/nvgpu.h> | 30 | #include <uapi/linux/nvgpu.h> |
32 | #include <trace/events/gk20a.h> | 31 | #include <trace/events/gk20a.h> |
33 | 32 | ||
@@ -46,6 +45,7 @@ | |||
46 | #include <nvgpu/bug.h> | 45 | #include <nvgpu/bug.h> |
47 | #include <nvgpu/log2.h> | 46 | #include <nvgpu/log2.h> |
48 | #include <nvgpu/enabled.h> | 47 | #include <nvgpu/enabled.h> |
48 | #include <nvgpu/vidmem.h> | ||
49 | 49 | ||
50 | #include <nvgpu/linux/dma.h> | 50 | #include <nvgpu/linux/dma.h> |
51 | 51 | ||
@@ -71,35 +71,6 @@ | |||
71 | */ | 71 | */ |
72 | #include "common/linux/vm_priv.h" | 72 | #include "common/linux/vm_priv.h" |
73 | 73 | ||
74 | #if defined(CONFIG_GK20A_VIDMEM) | ||
75 | static void gk20a_vidmem_clear_mem_worker(struct work_struct *work); | ||
76 | #endif | ||
77 | |||
78 | void set_vidmem_page_alloc(struct scatterlist *sgl, u64 addr) | ||
79 | { | ||
80 | /* set bit 0 to indicate vidmem allocation */ | ||
81 | sg_dma_address(sgl) = (addr | 1ULL); | ||
82 | } | ||
83 | |||
84 | bool is_vidmem_page_alloc(u64 addr) | ||
85 | { | ||
86 | return !!(addr & 1ULL); | ||
87 | } | ||
88 | |||
89 | struct nvgpu_page_alloc *get_vidmem_page_alloc(struct scatterlist *sgl) | ||
90 | { | ||
91 | u64 addr; | ||
92 | |||
93 | addr = sg_dma_address(sgl); | ||
94 | |||
95 | if (is_vidmem_page_alloc(addr)) | ||
96 | addr = addr & ~1ULL; | ||
97 | else | ||
98 | WARN_ON(1); | ||
99 | |||
100 | return (struct nvgpu_page_alloc *)(uintptr_t)addr; | ||
101 | } | ||
102 | |||
103 | /* | 74 | /* |
104 | * GPU mapping life cycle | 75 | * GPU mapping life cycle |
105 | * ====================== | 76 | * ====================== |
@@ -137,8 +108,6 @@ static int __must_check gk20a_init_hwpm(struct mm_gk20a *mm); | |||
137 | static int __must_check gk20a_init_cde_vm(struct mm_gk20a *mm); | 108 | static int __must_check gk20a_init_cde_vm(struct mm_gk20a *mm); |
138 | static int __must_check gk20a_init_ce_vm(struct mm_gk20a *mm); | 109 | static int __must_check gk20a_init_ce_vm(struct mm_gk20a *mm); |
139 | 110 | ||
140 | static struct gk20a *gk20a_vidmem_buf_owner(struct dma_buf *dmabuf); | ||
141 | |||
142 | struct gk20a_dmabuf_priv { | 111 | struct gk20a_dmabuf_priv { |
143 | struct nvgpu_mutex lock; | 112 | struct nvgpu_mutex lock; |
144 | 113 | ||
@@ -157,14 +126,6 @@ struct gk20a_dmabuf_priv { | |||
157 | u64 buffer_id; | 126 | u64 buffer_id; |
158 | }; | 127 | }; |
159 | 128 | ||
160 | struct gk20a_vidmem_buf { | ||
161 | struct gk20a *g; | ||
162 | struct nvgpu_mem *mem; | ||
163 | struct dma_buf *dmabuf; | ||
164 | void *dmabuf_priv; | ||
165 | void (*dmabuf_priv_delete)(void *); | ||
166 | }; | ||
167 | |||
168 | static int gk20a_comptaglines_alloc(struct gk20a_comptag_allocator *allocator, | 129 | static int gk20a_comptaglines_alloc(struct gk20a_comptag_allocator *allocator, |
169 | u32 *offset, u32 len) | 130 | u32 *offset, u32 len) |
170 | { | 131 | { |
@@ -331,9 +292,6 @@ int gk20a_alloc_comptags(struct gk20a *g, | |||
331 | return 0; | 292 | return 0; |
332 | } | 293 | } |
333 | 294 | ||
334 | |||
335 | |||
336 | |||
337 | static int gk20a_init_mm_reset_enable_hw(struct gk20a *g) | 295 | static int gk20a_init_mm_reset_enable_hw(struct gk20a *g) |
338 | { | 296 | { |
339 | gk20a_dbg_fn(""); | 297 | gk20a_dbg_fn(""); |
@@ -359,14 +317,6 @@ static int gk20a_init_mm_reset_enable_hw(struct gk20a *g) | |||
359 | return 0; | 317 | return 0; |
360 | } | 318 | } |
361 | 319 | ||
362 | static void gk20a_vidmem_destroy(struct gk20a *g) | ||
363 | { | ||
364 | #if defined(CONFIG_GK20A_VIDMEM) | ||
365 | if (nvgpu_alloc_initialized(&g->mm.vidmem.allocator)) | ||
366 | nvgpu_alloc_destroy(&g->mm.vidmem.allocator); | ||
367 | #endif | ||
368 | } | ||
369 | |||
370 | static void gk20a_remove_mm_ce_support(struct mm_gk20a *mm) | 320 | static void gk20a_remove_mm_ce_support(struct mm_gk20a *mm) |
371 | { | 321 | { |
372 | struct gk20a *g = gk20a_from_mm(mm); | 322 | struct gk20a *g = gk20a_from_mm(mm); |
@@ -409,143 +359,6 @@ static int gk20a_alloc_sysmem_flush(struct gk20a *g) | |||
409 | return nvgpu_dma_alloc_sys(g, SZ_4K, &g->mm.sysmem_flush); | 359 | return nvgpu_dma_alloc_sys(g, SZ_4K, &g->mm.sysmem_flush); |
410 | } | 360 | } |
411 | 361 | ||
412 | #if defined(CONFIG_GK20A_VIDMEM) | ||
413 | static int gk20a_vidmem_clear_all(struct gk20a *g) | ||
414 | { | ||
415 | struct mm_gk20a *mm = &g->mm; | ||
416 | struct gk20a_fence *gk20a_fence_out = NULL; | ||
417 | u64 region2_base = 0; | ||
418 | int err = 0; | ||
419 | |||
420 | if (mm->vidmem.ce_ctx_id == (u32)~0) | ||
421 | return -EINVAL; | ||
422 | |||
423 | err = gk20a_ce_execute_ops(g, | ||
424 | mm->vidmem.ce_ctx_id, | ||
425 | 0, | ||
426 | mm->vidmem.base, | ||
427 | mm->vidmem.bootstrap_base - mm->vidmem.base, | ||
428 | 0x00000000, | ||
429 | NVGPU_CE_DST_LOCATION_LOCAL_FB, | ||
430 | NVGPU_CE_MEMSET, | ||
431 | NULL, | ||
432 | 0, | ||
433 | NULL); | ||
434 | if (err) { | ||
435 | nvgpu_err(g, | ||
436 | "Failed to clear vidmem region 1 : %d", err); | ||
437 | return err; | ||
438 | } | ||
439 | |||
440 | region2_base = mm->vidmem.bootstrap_base + mm->vidmem.bootstrap_size; | ||
441 | |||
442 | err = gk20a_ce_execute_ops(g, | ||
443 | mm->vidmem.ce_ctx_id, | ||
444 | 0, | ||
445 | region2_base, | ||
446 | mm->vidmem.size - region2_base, | ||
447 | 0x00000000, | ||
448 | NVGPU_CE_DST_LOCATION_LOCAL_FB, | ||
449 | NVGPU_CE_MEMSET, | ||
450 | NULL, | ||
451 | 0, | ||
452 | &gk20a_fence_out); | ||
453 | if (err) { | ||
454 | nvgpu_err(g, | ||
455 | "Failed to clear vidmem region 2 : %d", err); | ||
456 | return err; | ||
457 | } | ||
458 | |||
459 | if (gk20a_fence_out) { | ||
460 | struct nvgpu_timeout timeout; | ||
461 | |||
462 | nvgpu_timeout_init(g, &timeout, | ||
463 | gk20a_get_gr_idle_timeout(g), | ||
464 | NVGPU_TIMER_CPU_TIMER); | ||
465 | |||
466 | do { | ||
467 | err = gk20a_fence_wait(g, gk20a_fence_out, | ||
468 | gk20a_get_gr_idle_timeout(g)); | ||
469 | } while (err == -ERESTARTSYS && | ||
470 | !nvgpu_timeout_expired(&timeout)); | ||
471 | |||
472 | gk20a_fence_put(gk20a_fence_out); | ||
473 | if (err) { | ||
474 | nvgpu_err(g, | ||
475 | "fence wait failed for CE execute ops"); | ||
476 | return err; | ||
477 | } | ||
478 | } | ||
479 | |||
480 | mm->vidmem.cleared = true; | ||
481 | |||
482 | return 0; | ||
483 | } | ||
484 | #endif | ||
485 | |||
486 | static int gk20a_init_vidmem(struct mm_gk20a *mm) | ||
487 | { | ||
488 | #if defined(CONFIG_GK20A_VIDMEM) | ||
489 | struct gk20a *g = mm->g; | ||
490 | size_t size = g->ops.mm.get_vidmem_size ? | ||
491 | g->ops.mm.get_vidmem_size(g) : 0; | ||
492 | u64 bootstrap_base, bootstrap_size, base; | ||
493 | u64 default_page_size = SZ_64K; | ||
494 | int err; | ||
495 | |||
496 | static struct nvgpu_alloc_carveout wpr_co = | ||
497 | NVGPU_CARVEOUT("wpr-region", 0, SZ_16M); | ||
498 | |||
499 | if (!size) | ||
500 | return 0; | ||
501 | |||
502 | wpr_co.base = size - SZ_256M; | ||
503 | bootstrap_base = wpr_co.base; | ||
504 | bootstrap_size = SZ_16M; | ||
505 | base = default_page_size; | ||
506 | |||
507 | /* | ||
508 | * Bootstrap allocator for use before the CE is initialized (CE | ||
509 | * initialization requires vidmem but we want to use the CE to zero | ||
510 | * out vidmem before allocating it... | ||
511 | */ | ||
512 | err = nvgpu_page_allocator_init(g, &g->mm.vidmem.bootstrap_allocator, | ||
513 | "vidmem-bootstrap", | ||
514 | bootstrap_base, bootstrap_size, | ||
515 | SZ_4K, 0); | ||
516 | |||
517 | err = nvgpu_page_allocator_init(g, &g->mm.vidmem.allocator, | ||
518 | "vidmem", | ||
519 | base, size - base, | ||
520 | default_page_size, | ||
521 | GPU_ALLOC_4K_VIDMEM_PAGES); | ||
522 | if (err) { | ||
523 | nvgpu_err(g, "Failed to register vidmem for size %zu: %d", | ||
524 | size, err); | ||
525 | return err; | ||
526 | } | ||
527 | |||
528 | /* Reserve bootstrap region in vidmem allocator */ | ||
529 | nvgpu_alloc_reserve_carveout(&g->mm.vidmem.allocator, &wpr_co); | ||
530 | |||
531 | mm->vidmem.base = base; | ||
532 | mm->vidmem.size = size - base; | ||
533 | mm->vidmem.bootstrap_base = bootstrap_base; | ||
534 | mm->vidmem.bootstrap_size = bootstrap_size; | ||
535 | |||
536 | nvgpu_mutex_init(&mm->vidmem.first_clear_mutex); | ||
537 | |||
538 | INIT_WORK(&mm->vidmem.clear_mem_worker, gk20a_vidmem_clear_mem_worker); | ||
539 | nvgpu_atomic64_set(&mm->vidmem.bytes_pending, 0); | ||
540 | nvgpu_init_list_node(&mm->vidmem.clear_list_head); | ||
541 | nvgpu_mutex_init(&mm->vidmem.clear_list_mutex); | ||
542 | |||
543 | gk20a_dbg_info("registered vidmem: %zu MB", size / SZ_1M); | ||
544 | |||
545 | #endif | ||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | int gk20a_init_mm_setup_sw(struct gk20a *g) | 362 | int gk20a_init_mm_setup_sw(struct gk20a *g) |
550 | { | 363 | { |
551 | struct mm_gk20a *mm = &g->mm; | 364 | struct mm_gk20a *mm = &g->mm; |
@@ -904,358 +717,6 @@ int setup_buffer_kind_and_compression(struct vm_gk20a *vm, | |||
904 | return 0; | 717 | return 0; |
905 | } | 718 | } |
906 | 719 | ||
907 | enum nvgpu_aperture gk20a_dmabuf_aperture(struct gk20a *g, | ||
908 | struct dma_buf *dmabuf) | ||
909 | { | ||
910 | struct gk20a *buf_owner = gk20a_vidmem_buf_owner(dmabuf); | ||
911 | bool unified_memory = nvgpu_is_enabled(g, NVGPU_MM_UNIFIED_MEMORY); | ||
912 | |||
913 | if (buf_owner == NULL) { | ||
914 | /* Not nvgpu-allocated, assume system memory */ | ||
915 | return APERTURE_SYSMEM; | ||
916 | } else if (WARN_ON(buf_owner == g && unified_memory)) { | ||
917 | /* Looks like our video memory, but this gpu doesn't support | ||
918 | * it. Warn about a bug and bail out */ | ||
919 | nvgpu_warn(g, | ||
920 | "dmabuf is our vidmem but we don't have local vidmem"); | ||
921 | return APERTURE_INVALID; | ||
922 | } else if (buf_owner != g) { | ||
923 | /* Someone else's vidmem */ | ||
924 | return APERTURE_INVALID; | ||
925 | } else { | ||
926 | /* Yay, buf_owner == g */ | ||
927 | return APERTURE_VIDMEM; | ||
928 | } | ||
929 | } | ||
930 | |||
931 | #if defined(CONFIG_GK20A_VIDMEM) | ||
932 | static struct sg_table *gk20a_vidbuf_map_dma_buf( | ||
933 | struct dma_buf_attachment *attach, enum dma_data_direction dir) | ||
934 | { | ||
935 | struct gk20a_vidmem_buf *buf = attach->dmabuf->priv; | ||
936 | |||
937 | return buf->mem->priv.sgt; | ||
938 | } | ||
939 | |||
940 | static void gk20a_vidbuf_unmap_dma_buf(struct dma_buf_attachment *attach, | ||
941 | struct sg_table *sgt, | ||
942 | enum dma_data_direction dir) | ||
943 | { | ||
944 | } | ||
945 | |||
946 | static void gk20a_vidbuf_release(struct dma_buf *dmabuf) | ||
947 | { | ||
948 | struct gk20a_vidmem_buf *buf = dmabuf->priv; | ||
949 | |||
950 | gk20a_dbg_fn(""); | ||
951 | |||
952 | if (buf->dmabuf_priv) | ||
953 | buf->dmabuf_priv_delete(buf->dmabuf_priv); | ||
954 | |||
955 | nvgpu_dma_free(buf->g, buf->mem); | ||
956 | nvgpu_kfree(buf->g, buf); | ||
957 | } | ||
958 | |||
959 | static void *gk20a_vidbuf_kmap(struct dma_buf *dmabuf, unsigned long page_num) | ||
960 | { | ||
961 | WARN_ON("Not supported"); | ||
962 | return NULL; | ||
963 | } | ||
964 | |||
965 | static void *gk20a_vidbuf_kmap_atomic(struct dma_buf *dmabuf, | ||
966 | unsigned long page_num) | ||
967 | { | ||
968 | WARN_ON("Not supported"); | ||
969 | return NULL; | ||
970 | } | ||
971 | |||
972 | static int gk20a_vidbuf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) | ||
973 | { | ||
974 | return -EINVAL; | ||
975 | } | ||
976 | |||
977 | static int gk20a_vidbuf_set_private(struct dma_buf *dmabuf, | ||
978 | struct device *dev, void *priv, void (*delete)(void *priv)) | ||
979 | { | ||
980 | struct gk20a_vidmem_buf *buf = dmabuf->priv; | ||
981 | |||
982 | buf->dmabuf_priv = priv; | ||
983 | buf->dmabuf_priv_delete = delete; | ||
984 | |||
985 | return 0; | ||
986 | } | ||
987 | |||
988 | static void *gk20a_vidbuf_get_private(struct dma_buf *dmabuf, | ||
989 | struct device *dev) | ||
990 | { | ||
991 | struct gk20a_vidmem_buf *buf = dmabuf->priv; | ||
992 | |||
993 | return buf->dmabuf_priv; | ||
994 | } | ||
995 | |||
996 | static const struct dma_buf_ops gk20a_vidbuf_ops = { | ||
997 | .map_dma_buf = gk20a_vidbuf_map_dma_buf, | ||
998 | .unmap_dma_buf = gk20a_vidbuf_unmap_dma_buf, | ||
999 | .release = gk20a_vidbuf_release, | ||
1000 | .kmap_atomic = gk20a_vidbuf_kmap_atomic, | ||
1001 | .kmap = gk20a_vidbuf_kmap, | ||
1002 | .mmap = gk20a_vidbuf_mmap, | ||
1003 | .set_drvdata = gk20a_vidbuf_set_private, | ||
1004 | .get_drvdata = gk20a_vidbuf_get_private, | ||
1005 | }; | ||
1006 | |||
1007 | static struct dma_buf *gk20a_vidbuf_export(struct gk20a_vidmem_buf *buf) | ||
1008 | { | ||
1009 | DEFINE_DMA_BUF_EXPORT_INFO(exp_info); | ||
1010 | |||
1011 | exp_info.priv = buf; | ||
1012 | exp_info.ops = &gk20a_vidbuf_ops; | ||
1013 | exp_info.size = buf->mem->size; | ||
1014 | exp_info.flags = O_RDWR; | ||
1015 | |||
1016 | return dma_buf_export(&exp_info); | ||
1017 | } | ||
1018 | #endif | ||
1019 | |||
1020 | static struct gk20a *gk20a_vidmem_buf_owner(struct dma_buf *dmabuf) | ||
1021 | { | ||
1022 | #if defined(CONFIG_GK20A_VIDMEM) | ||
1023 | struct gk20a_vidmem_buf *buf = dmabuf->priv; | ||
1024 | |||
1025 | if (dmabuf->ops != &gk20a_vidbuf_ops) | ||
1026 | return NULL; | ||
1027 | |||
1028 | return buf->g; | ||
1029 | #else | ||
1030 | return NULL; | ||
1031 | #endif | ||
1032 | } | ||
1033 | |||
1034 | int gk20a_vidmem_buf_alloc(struct gk20a *g, size_t bytes) | ||
1035 | { | ||
1036 | #if defined(CONFIG_GK20A_VIDMEM) | ||
1037 | struct gk20a_vidmem_buf *buf; | ||
1038 | int err = 0, fd; | ||
1039 | |||
1040 | gk20a_dbg_fn(""); | ||
1041 | |||
1042 | buf = nvgpu_kzalloc(g, sizeof(*buf)); | ||
1043 | if (!buf) | ||
1044 | return -ENOMEM; | ||
1045 | |||
1046 | buf->g = g; | ||
1047 | |||
1048 | if (!g->mm.vidmem.cleared) { | ||
1049 | nvgpu_mutex_acquire(&g->mm.vidmem.first_clear_mutex); | ||
1050 | if (!g->mm.vidmem.cleared) { | ||
1051 | err = gk20a_vidmem_clear_all(g); | ||
1052 | if (err) { | ||
1053 | nvgpu_err(g, | ||
1054 | "failed to clear whole vidmem"); | ||
1055 | goto err_kfree; | ||
1056 | } | ||
1057 | } | ||
1058 | nvgpu_mutex_release(&g->mm.vidmem.first_clear_mutex); | ||
1059 | } | ||
1060 | |||
1061 | buf->mem = nvgpu_kzalloc(g, sizeof(struct nvgpu_mem)); | ||
1062 | if (!buf->mem) | ||
1063 | goto err_kfree; | ||
1064 | |||
1065 | buf->mem->mem_flags |= NVGPU_MEM_FLAG_USER_MEM; | ||
1066 | |||
1067 | err = nvgpu_dma_alloc_vid(g, bytes, buf->mem); | ||
1068 | if (err) | ||
1069 | goto err_memfree; | ||
1070 | |||
1071 | buf->dmabuf = gk20a_vidbuf_export(buf); | ||
1072 | if (IS_ERR(buf->dmabuf)) { | ||
1073 | err = PTR_ERR(buf->dmabuf); | ||
1074 | goto err_bfree; | ||
1075 | } | ||
1076 | |||
1077 | fd = tegra_alloc_fd(current->files, 1024, O_RDWR); | ||
1078 | if (fd < 0) { | ||
1079 | /* ->release frees what we have done */ | ||
1080 | dma_buf_put(buf->dmabuf); | ||
1081 | return fd; | ||
1082 | } | ||
1083 | |||
1084 | /* fclose() on this drops one ref, freeing the dma buf */ | ||
1085 | fd_install(fd, buf->dmabuf->file); | ||
1086 | |||
1087 | return fd; | ||
1088 | |||
1089 | err_bfree: | ||
1090 | nvgpu_dma_free(g, buf->mem); | ||
1091 | err_memfree: | ||
1092 | nvgpu_kfree(g, buf->mem); | ||
1093 | err_kfree: | ||
1094 | nvgpu_kfree(g, buf); | ||
1095 | return err; | ||
1096 | #else | ||
1097 | return -ENOSYS; | ||
1098 | #endif | ||
1099 | } | ||
1100 | |||
1101 | int gk20a_vidmem_get_space(struct gk20a *g, u64 *space) | ||
1102 | { | ||
1103 | #if defined(CONFIG_GK20A_VIDMEM) | ||
1104 | struct nvgpu_allocator *allocator = &g->mm.vidmem.allocator; | ||
1105 | |||
1106 | gk20a_dbg_fn(""); | ||
1107 | |||
1108 | if (!nvgpu_alloc_initialized(allocator)) | ||
1109 | return -ENOSYS; | ||
1110 | |||
1111 | nvgpu_mutex_acquire(&g->mm.vidmem.clear_list_mutex); | ||
1112 | *space = nvgpu_alloc_space(allocator) + | ||
1113 | nvgpu_atomic64_read(&g->mm.vidmem.bytes_pending); | ||
1114 | nvgpu_mutex_release(&g->mm.vidmem.clear_list_mutex); | ||
1115 | return 0; | ||
1116 | #else | ||
1117 | return -ENOSYS; | ||
1118 | #endif | ||
1119 | } | ||
1120 | |||
1121 | int gk20a_vidbuf_access_memory(struct gk20a *g, struct dma_buf *dmabuf, | ||
1122 | void *buffer, u64 offset, u64 size, u32 cmd) | ||
1123 | { | ||
1124 | #if defined(CONFIG_GK20A_VIDMEM) | ||
1125 | struct gk20a_vidmem_buf *vidmem_buf; | ||
1126 | struct nvgpu_mem *mem; | ||
1127 | int err = 0; | ||
1128 | |||
1129 | if (gk20a_dmabuf_aperture(g, dmabuf) != APERTURE_VIDMEM) | ||
1130 | return -EINVAL; | ||
1131 | |||
1132 | vidmem_buf = dmabuf->priv; | ||
1133 | mem = vidmem_buf->mem; | ||
1134 | |||
1135 | switch (cmd) { | ||
1136 | case NVGPU_DBG_GPU_IOCTL_ACCESS_FB_MEMORY_CMD_READ: | ||
1137 | nvgpu_mem_rd_n(g, mem, offset, buffer, size); | ||
1138 | break; | ||
1139 | |||
1140 | case NVGPU_DBG_GPU_IOCTL_ACCESS_FB_MEMORY_CMD_WRITE: | ||
1141 | nvgpu_mem_wr_n(g, mem, offset, buffer, size); | ||
1142 | break; | ||
1143 | |||
1144 | default: | ||
1145 | err = -EINVAL; | ||
1146 | } | ||
1147 | |||
1148 | return err; | ||
1149 | #else | ||
1150 | return -ENOSYS; | ||
1151 | #endif | ||
1152 | } | ||
1153 | |||
1154 | #if defined(CONFIG_GK20A_VIDMEM) | ||
1155 | static int gk20a_gmmu_clear_vidmem_mem(struct gk20a *g, struct nvgpu_mem *mem) | ||
1156 | { | ||
1157 | struct gk20a_fence *gk20a_fence_out = NULL; | ||
1158 | struct gk20a_fence *gk20a_last_fence = NULL; | ||
1159 | struct nvgpu_page_alloc *alloc = NULL; | ||
1160 | struct nvgpu_sgt *sgt = NULL; | ||
1161 | void *sgl = NULL; | ||
1162 | int err = 0; | ||
1163 | |||
1164 | if (g->mm.vidmem.ce_ctx_id == (u32)~0) | ||
1165 | return -EINVAL; | ||
1166 | |||
1167 | alloc = get_vidmem_page_alloc(mem->priv.sgt->sgl); | ||
1168 | |||
1169 | sgt = &alloc->sgt; | ||
1170 | sgl = sgt->sgl; | ||
1171 | while (sgl) { | ||
1172 | if (gk20a_last_fence) | ||
1173 | gk20a_fence_put(gk20a_last_fence); | ||
1174 | |||
1175 | err = gk20a_ce_execute_ops(g, | ||
1176 | g->mm.vidmem.ce_ctx_id, | ||
1177 | 0, | ||
1178 | nvgpu_sgt_get_phys(sgt, sgl), | ||
1179 | nvgpu_sgt_get_length(sgt, sgl), | ||
1180 | 0x00000000, | ||
1181 | NVGPU_CE_DST_LOCATION_LOCAL_FB, | ||
1182 | NVGPU_CE_MEMSET, | ||
1183 | NULL, | ||
1184 | 0, | ||
1185 | &gk20a_fence_out); | ||
1186 | |||
1187 | if (err) { | ||
1188 | nvgpu_err(g, | ||
1189 | "Failed gk20a_ce_execute_ops[%d]", err); | ||
1190 | return err; | ||
1191 | } | ||
1192 | |||
1193 | gk20a_last_fence = gk20a_fence_out; | ||
1194 | sgl = nvgpu_sgt_get_next(sgt, sgl); | ||
1195 | } | ||
1196 | |||
1197 | if (gk20a_last_fence) { | ||
1198 | struct nvgpu_timeout timeout; | ||
1199 | |||
1200 | nvgpu_timeout_init(g, &timeout, | ||
1201 | gk20a_get_gr_idle_timeout(g), | ||
1202 | NVGPU_TIMER_CPU_TIMER); | ||
1203 | |||
1204 | do { | ||
1205 | err = gk20a_fence_wait(g, gk20a_last_fence, | ||
1206 | gk20a_get_gr_idle_timeout(g)); | ||
1207 | } while (err == -ERESTARTSYS && | ||
1208 | !nvgpu_timeout_expired(&timeout)); | ||
1209 | |||
1210 | gk20a_fence_put(gk20a_last_fence); | ||
1211 | if (err) | ||
1212 | nvgpu_err(g, | ||
1213 | "fence wait failed for CE execute ops"); | ||
1214 | } | ||
1215 | |||
1216 | return err; | ||
1217 | } | ||
1218 | #endif | ||
1219 | |||
1220 | #if defined(CONFIG_GK20A_VIDMEM) | ||
1221 | static struct nvgpu_mem *get_pending_mem_desc(struct mm_gk20a *mm) | ||
1222 | { | ||
1223 | struct nvgpu_mem *mem = NULL; | ||
1224 | |||
1225 | nvgpu_mutex_acquire(&mm->vidmem.clear_list_mutex); | ||
1226 | if (!nvgpu_list_empty(&mm->vidmem.clear_list_head)) { | ||
1227 | mem = nvgpu_list_first_entry(&mm->vidmem.clear_list_head, | ||
1228 | nvgpu_mem, clear_list_entry); | ||
1229 | nvgpu_list_del(&mem->clear_list_entry); | ||
1230 | } | ||
1231 | nvgpu_mutex_release(&mm->vidmem.clear_list_mutex); | ||
1232 | |||
1233 | return mem; | ||
1234 | } | ||
1235 | |||
1236 | static void gk20a_vidmem_clear_mem_worker(struct work_struct *work) | ||
1237 | { | ||
1238 | struct mm_gk20a *mm = container_of(work, struct mm_gk20a, | ||
1239 | vidmem.clear_mem_worker); | ||
1240 | struct gk20a *g = mm->g; | ||
1241 | struct nvgpu_mem *mem; | ||
1242 | |||
1243 | while ((mem = get_pending_mem_desc(mm)) != NULL) { | ||
1244 | gk20a_gmmu_clear_vidmem_mem(g, mem); | ||
1245 | nvgpu_free(mem->allocator, | ||
1246 | (u64)get_vidmem_page_alloc(mem->priv.sgt->sgl)); | ||
1247 | nvgpu_free_sgtable(g, &mem->priv.sgt); | ||
1248 | |||
1249 | WARN_ON(nvgpu_atomic64_sub_return(mem->aligned_size, | ||
1250 | &g->mm.vidmem.bytes_pending) < 0); | ||
1251 | mem->size = 0; | ||
1252 | mem->aperture = APERTURE_INVALID; | ||
1253 | |||
1254 | nvgpu_kfree(g, mem); | ||
1255 | } | ||
1256 | } | ||
1257 | #endif | ||
1258 | |||
1259 | dma_addr_t gk20a_mm_gpuva_to_iova_base(struct vm_gk20a *vm, u64 gpu_vaddr) | 720 | dma_addr_t gk20a_mm_gpuva_to_iova_base(struct vm_gk20a *vm, u64 gpu_vaddr) |
1260 | { | 721 | { |
1261 | struct nvgpu_mapped_buf *buffer; | 722 | struct nvgpu_mapped_buf *buffer; |
diff --git a/drivers/gpu/nvgpu/gk20a/mm_gk20a.h b/drivers/gpu/nvgpu/gk20a/mm_gk20a.h index 9f03a495..7029e0e0 100644 --- a/drivers/gpu/nvgpu/gk20a/mm_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/mm_gk20a.h | |||
@@ -320,10 +320,6 @@ enum gmmu_pgsz_gk20a __get_pte_size_fixed_map(struct vm_gk20a *vm, | |||
320 | u64 base, u64 size); | 320 | u64 base, u64 size); |
321 | enum gmmu_pgsz_gk20a __get_pte_size(struct vm_gk20a *vm, u64 base, u64 size); | 321 | enum gmmu_pgsz_gk20a __get_pte_size(struct vm_gk20a *vm, u64 base, u64 size); |
322 | 322 | ||
323 | void set_vidmem_page_alloc(struct scatterlist *sgl, u64 addr); | ||
324 | bool is_vidmem_page_alloc(u64 addr); | ||
325 | struct nvgpu_page_alloc *get_vidmem_page_alloc(struct scatterlist *sgl); | ||
326 | |||
327 | #if 0 /*related to addr bits above, concern below TBD on which is accurate */ | 323 | #if 0 /*related to addr bits above, concern below TBD on which is accurate */ |
328 | #define bar1_instance_block_shift_gk20a() (max_physaddr_bits_gk20a() -\ | 324 | #define bar1_instance_block_shift_gk20a() (max_physaddr_bits_gk20a() -\ |
329 | bus_bar1_block_ptr_s()) | 325 | bus_bar1_block_ptr_s()) |
@@ -400,11 +396,6 @@ int gk20a_vm_bind_channel(struct gk20a_as_share *as_share, | |||
400 | struct channel_gk20a *ch); | 396 | struct channel_gk20a *ch); |
401 | int __gk20a_vm_bind_channel(struct vm_gk20a *vm, struct channel_gk20a *ch); | 397 | int __gk20a_vm_bind_channel(struct vm_gk20a *vm, struct channel_gk20a *ch); |
402 | 398 | ||
403 | int gk20a_vidmem_buf_alloc(struct gk20a *g, size_t bytes); | ||
404 | int gk20a_vidmem_get_space(struct gk20a *g, u64 *space); | ||
405 | int gk20a_vidbuf_access_memory(struct gk20a *g, struct dma_buf *dmabuf, | ||
406 | void *buffer, u64 offset, u64 size, u32 cmd); | ||
407 | |||
408 | void gk20a_get_comptags(struct device *dev, struct dma_buf *dmabuf, | 399 | void gk20a_get_comptags(struct device *dev, struct dma_buf *dmabuf, |
409 | struct gk20a_comptags *comptags); | 400 | struct gk20a_comptags *comptags); |
410 | dma_addr_t gk20a_mm_gpuva_to_iova_base(struct vm_gk20a *vm, u64 gpu_vaddr); | 401 | dma_addr_t gk20a_mm_gpuva_to_iova_base(struct vm_gk20a *vm, u64 gpu_vaddr); |
diff --git a/drivers/gpu/nvgpu/include/nvgpu/vidmem.h b/drivers/gpu/nvgpu/include/nvgpu/vidmem.h new file mode 100644 index 00000000..a5d0ae11 --- /dev/null +++ b/drivers/gpu/nvgpu/include/nvgpu/vidmem.h | |||
@@ -0,0 +1,139 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | * DEALINGS IN THE SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #ifndef __NVGPU_VIDMEM_H__ | ||
24 | #define __NVGPU_VIDMEM_H__ | ||
25 | |||
26 | #include <nvgpu/types.h> | ||
27 | #include <nvgpu/errno.h> | ||
28 | |||
29 | struct scatterlist; | ||
30 | struct dma_buf; | ||
31 | struct work_struct; | ||
32 | |||
33 | struct gk20a; | ||
34 | struct mm_gk20a; | ||
35 | struct nvgpu_mem; | ||
36 | |||
37 | struct gk20a_vidmem_buf { | ||
38 | struct gk20a *g; | ||
39 | struct nvgpu_mem *mem; | ||
40 | struct dma_buf *dmabuf; | ||
41 | void *dmabuf_priv; | ||
42 | void (*dmabuf_priv_delete)(void *); | ||
43 | }; | ||
44 | |||
45 | #if defined(CONFIG_GK20A_VIDMEM) | ||
46 | |||
47 | struct nvgpu_page_alloc *get_vidmem_page_alloc(struct scatterlist *sgl); | ||
48 | void set_vidmem_page_alloc(struct scatterlist *sgl, u64 addr); | ||
49 | bool is_vidmem_page_alloc(u64 addr); | ||
50 | int gk20a_vidmem_buf_alloc(struct gk20a *g, size_t bytes); | ||
51 | int gk20a_vidmem_get_space(struct gk20a *g, u64 *space); | ||
52 | |||
53 | struct nvgpu_mem *get_pending_mem_desc(struct mm_gk20a *mm); | ||
54 | |||
55 | void gk20a_vidmem_destroy(struct gk20a *g); | ||
56 | int gk20a_init_vidmem(struct mm_gk20a *mm); | ||
57 | int gk20a_vidmem_clear_all(struct gk20a *g); | ||
58 | |||
59 | void gk20a_vidmem_clear_mem_worker(struct work_struct *work); | ||
60 | int gk20a_gmmu_clear_vidmem_mem(struct gk20a *g, struct nvgpu_mem *mem); | ||
61 | |||
62 | /* | ||
63 | * Will need to be moved later on once we have the Linux vidmem.h file. | ||
64 | */ | ||
65 | struct gk20a *gk20a_vidmem_buf_owner(struct dma_buf *dmabuf); | ||
66 | int gk20a_vidbuf_access_memory(struct gk20a *g, struct dma_buf *dmabuf, | ||
67 | void *buffer, u64 offset, u64 size, u32 cmd); | ||
68 | |||
69 | #else /* !defined(CONFIG_GK20A_VIDMEM) */ | ||
70 | |||
71 | /* | ||
72 | * When VIDMEM support is not present this interface is used. | ||
73 | */ | ||
74 | |||
75 | static inline struct nvgpu_page_alloc * | ||
76 | get_vidmem_page_alloc(struct scatterlist *sgl) | ||
77 | { | ||
78 | return NULL; | ||
79 | } | ||
80 | |||
81 | static inline void set_vidmem_page_alloc(struct scatterlist *sgl, u64 addr) | ||
82 | { | ||
83 | } | ||
84 | |||
85 | static inline bool is_vidmem_page_alloc(u64 addr) | ||
86 | { | ||
87 | return false; | ||
88 | } | ||
89 | |||
90 | static inline int gk20a_vidmem_buf_alloc(struct gk20a *g, size_t bytes) | ||
91 | { | ||
92 | return -ENOSYS; | ||
93 | } | ||
94 | static inline int gk20a_vidmem_get_space(struct gk20a *g, u64 *space) | ||
95 | { | ||
96 | return -ENOSYS; | ||
97 | } | ||
98 | |||
99 | static inline struct nvgpu_mem *get_pending_mem_desc(struct mm_gk20a *mm) | ||
100 | { | ||
101 | return NULL; | ||
102 | } | ||
103 | |||
104 | static inline void gk20a_vidmem_destroy(struct gk20a *g) | ||
105 | { | ||
106 | } | ||
107 | |||
108 | static inline int gk20a_init_vidmem(struct mm_gk20a *mm) | ||
109 | { | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static inline int gk20a_vidmem_clear_all(struct gk20a *g) | ||
114 | { | ||
115 | return -ENOSYS; | ||
116 | } | ||
117 | |||
118 | static inline int gk20a_gmmu_clear_vidmem_mem(struct gk20a *g, | ||
119 | struct nvgpu_mem *mem) | ||
120 | { | ||
121 | return -ENOSYS; | ||
122 | } | ||
123 | |||
124 | static inline struct gk20a *gk20a_vidmem_buf_owner(struct dma_buf *dmabuf) | ||
125 | { | ||
126 | return NULL; | ||
127 | } | ||
128 | |||
129 | static inline int gk20a_vidbuf_access_memory(struct gk20a *g, | ||
130 | struct dma_buf *dmabuf, | ||
131 | void *buffer, u64 offset, | ||
132 | u64 size, u32 cmd) | ||
133 | { | ||
134 | return -ENOSYS; | ||
135 | } | ||
136 | |||
137 | #endif /* !defined(CONFIG_GK20A_VIDMEM) */ | ||
138 | |||
139 | #endif /* __NVGPU_VIDMEM_H__ */ | ||