summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu
diff options
context:
space:
mode:
authorAlex Waterman <alexw@nvidia.com>2017-07-31 15:32:07 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2017-10-10 11:01:04 -0400
commit3c37701377459fbea2b460e1b9c65a863dfb04b2 (patch)
tree60a57a260dc8bcbd81089af8e9e966074e3bc881 /drivers/gpu/nvgpu
parentb61306795b53647e8d1d4279417df1e1fe0f4b86 (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>
Diffstat (limited to 'drivers/gpu/nvgpu')
-rw-r--r--drivers/gpu/nvgpu/Makefile.nvgpu4
-rw-r--r--drivers/gpu/nvgpu/common/linux/dma.c1
-rw-r--r--drivers/gpu/nvgpu/common/linux/ioctl_ctrl.c1
-rw-r--r--drivers/gpu/nvgpu/common/linux/nvgpu_mem.c1
-rw-r--r--drivers/gpu/nvgpu/common/linux/vidmem.c268
-rw-r--r--drivers/gpu/nvgpu/common/linux/vm.c29
-rw-r--r--drivers/gpu/nvgpu/common/mm/gmmu.c1
-rw-r--r--drivers/gpu/nvgpu/common/mm/nvgpu_mem.c1
-rw-r--r--drivers/gpu/nvgpu/common/mm/vidmem.c259
-rw-r--r--drivers/gpu/nvgpu/common/pramin.c1
-rw-r--r--drivers/gpu/nvgpu/gk20a/dbg_gpu_gk20a.c1
-rw-r--r--drivers/gpu/nvgpu/gk20a/mm_gk20a.c541
-rw-r--r--drivers/gpu/nvgpu/gk20a/mm_gk20a.h9
-rw-r--r--drivers/gpu/nvgpu/include/nvgpu/vidmem.h139
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
124nvgpu-$(CONFIG_GK20A_VIDMEM) += \
125 common/mm/vidmem.o \
126 common/linux/vidmem.o
127
124nvgpu-$(CONFIG_DEBUG_FS) += \ 128nvgpu-$(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
34void 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
40bool is_vidmem_page_alloc(u64 addr)
41{
42 return !!(addr & 1ULL);
43}
44
45struct 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
59static 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
67static 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
73static 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
86static void *gk20a_vidbuf_kmap(struct dma_buf *dmabuf, unsigned long page_num)
87{
88 WARN_ON("Not supported");
89 return NULL;
90}
91
92static 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
99static int gk20a_vidbuf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
100{
101 return -EINVAL;
102}
103
104static 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
115static 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
123static 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
134static 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
146struct 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
156int 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
210err_bfree:
211 nvgpu_dma_free(g, buf->mem);
212err_memfree:
213 nvgpu_kfree(g, buf->mem);
214err_kfree:
215 nvgpu_kfree(g, buf);
216 return err;
217}
218
219int 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
248void 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 */
42enum 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
37static struct nvgpu_mapped_buf *__nvgpu_vm_find_mapped_buf_reverse( 66static 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
31void 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
37int 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
109int 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
170int 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
186int 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
246struct 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)
75static void gk20a_vidmem_clear_mem_worker(struct work_struct *work);
76#endif
77
78void 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
84bool is_vidmem_page_alloc(u64 addr)
85{
86 return !!(addr & 1ULL);
87}
88
89struct 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);
137static int __must_check gk20a_init_cde_vm(struct mm_gk20a *mm); 108static int __must_check gk20a_init_cde_vm(struct mm_gk20a *mm);
138static int __must_check gk20a_init_ce_vm(struct mm_gk20a *mm); 109static int __must_check gk20a_init_ce_vm(struct mm_gk20a *mm);
139 110
140static struct gk20a *gk20a_vidmem_buf_owner(struct dma_buf *dmabuf);
141
142struct gk20a_dmabuf_priv { 111struct 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
160struct 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
168static int gk20a_comptaglines_alloc(struct gk20a_comptag_allocator *allocator, 129static 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
337static int gk20a_init_mm_reset_enable_hw(struct gk20a *g) 295static 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
362static 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
370static void gk20a_remove_mm_ce_support(struct mm_gk20a *mm) 320static 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)
413static 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
486static 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
549int gk20a_init_mm_setup_sw(struct gk20a *g) 362int 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
907enum 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)
932static 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
940static 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
946static 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
959static void *gk20a_vidbuf_kmap(struct dma_buf *dmabuf, unsigned long page_num)
960{
961 WARN_ON("Not supported");
962 return NULL;
963}
964
965static 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
972static int gk20a_vidbuf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
973{
974 return -EINVAL;
975}
976
977static 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
988static 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
996static 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
1007static 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
1020static 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
1034int 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
1089err_bfree:
1090 nvgpu_dma_free(g, buf->mem);
1091err_memfree:
1092 nvgpu_kfree(g, buf->mem);
1093err_kfree:
1094 nvgpu_kfree(g, buf);
1095 return err;
1096#else
1097 return -ENOSYS;
1098#endif
1099}
1100
1101int 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
1121int 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)
1155static 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)
1221static 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
1236static 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
1259dma_addr_t gk20a_mm_gpuva_to_iova_base(struct vm_gk20a *vm, u64 gpu_vaddr) 720dma_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);
321enum gmmu_pgsz_gk20a __get_pte_size(struct vm_gk20a *vm, u64 base, u64 size); 321enum gmmu_pgsz_gk20a __get_pte_size(struct vm_gk20a *vm, u64 base, u64 size);
322 322
323void set_vidmem_page_alloc(struct scatterlist *sgl, u64 addr);
324bool is_vidmem_page_alloc(u64 addr);
325struct 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);
401int __gk20a_vm_bind_channel(struct vm_gk20a *vm, struct channel_gk20a *ch); 397int __gk20a_vm_bind_channel(struct vm_gk20a *vm, struct channel_gk20a *ch);
402 398
403int gk20a_vidmem_buf_alloc(struct gk20a *g, size_t bytes);
404int gk20a_vidmem_get_space(struct gk20a *g, u64 *space);
405int gk20a_vidbuf_access_memory(struct gk20a *g, struct dma_buf *dmabuf,
406 void *buffer, u64 offset, u64 size, u32 cmd);
407
408void gk20a_get_comptags(struct device *dev, struct dma_buf *dmabuf, 399void gk20a_get_comptags(struct device *dev, struct dma_buf *dmabuf,
409 struct gk20a_comptags *comptags); 400 struct gk20a_comptags *comptags);
410dma_addr_t gk20a_mm_gpuva_to_iova_base(struct vm_gk20a *vm, u64 gpu_vaddr); 401dma_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
29struct scatterlist;
30struct dma_buf;
31struct work_struct;
32
33struct gk20a;
34struct mm_gk20a;
35struct nvgpu_mem;
36
37struct 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
47struct nvgpu_page_alloc *get_vidmem_page_alloc(struct scatterlist *sgl);
48void set_vidmem_page_alloc(struct scatterlist *sgl, u64 addr);
49bool is_vidmem_page_alloc(u64 addr);
50int gk20a_vidmem_buf_alloc(struct gk20a *g, size_t bytes);
51int gk20a_vidmem_get_space(struct gk20a *g, u64 *space);
52
53struct nvgpu_mem *get_pending_mem_desc(struct mm_gk20a *mm);
54
55void gk20a_vidmem_destroy(struct gk20a *g);
56int gk20a_init_vidmem(struct mm_gk20a *mm);
57int gk20a_vidmem_clear_all(struct gk20a *g);
58
59void gk20a_vidmem_clear_mem_worker(struct work_struct *work);
60int 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 */
65struct gk20a *gk20a_vidmem_buf_owner(struct dma_buf *dmabuf);
66int 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
75static inline struct nvgpu_page_alloc *
76get_vidmem_page_alloc(struct scatterlist *sgl)
77{
78 return NULL;
79}
80
81static inline void set_vidmem_page_alloc(struct scatterlist *sgl, u64 addr)
82{
83}
84
85static inline bool is_vidmem_page_alloc(u64 addr)
86{
87 return false;
88}
89
90static inline int gk20a_vidmem_buf_alloc(struct gk20a *g, size_t bytes)
91{
92 return -ENOSYS;
93}
94static inline int gk20a_vidmem_get_space(struct gk20a *g, u64 *space)
95{
96 return -ENOSYS;
97}
98
99static inline struct nvgpu_mem *get_pending_mem_desc(struct mm_gk20a *mm)
100{
101 return NULL;
102}
103
104static inline void gk20a_vidmem_destroy(struct gk20a *g)
105{
106}
107
108static inline int gk20a_init_vidmem(struct mm_gk20a *mm)
109{
110 return 0;
111}
112
113static inline int gk20a_vidmem_clear_all(struct gk20a *g)
114{
115 return -ENOSYS;
116}
117
118static inline int gk20a_gmmu_clear_vidmem_mem(struct gk20a *g,
119 struct nvgpu_mem *mem)
120{
121 return -ENOSYS;
122}
123
124static inline struct gk20a *gk20a_vidmem_buf_owner(struct dma_buf *dmabuf)
125{
126 return NULL;
127}
128
129static 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__ */