diff options
Diffstat (limited to 'drivers/gpu/nvgpu/common/mm/vidmem.c')
-rw-r--r-- | drivers/gpu/nvgpu/common/mm/vidmem.c | 80 |
1 files changed, 79 insertions, 1 deletions
diff --git a/drivers/gpu/nvgpu/common/mm/vidmem.c b/drivers/gpu/nvgpu/common/mm/vidmem.c index c95cedec..18f46c03 100644 --- a/drivers/gpu/nvgpu/common/mm/vidmem.c +++ b/drivers/gpu/nvgpu/common/mm/vidmem.c | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #include <linux/scatterlist.h> | 23 | #include <linux/scatterlist.h> |
24 | 24 | ||
25 | #include <nvgpu/dma.h> | ||
25 | #include <nvgpu/vidmem.h> | 26 | #include <nvgpu/vidmem.h> |
26 | #include <nvgpu/page_allocator.h> | 27 | #include <nvgpu/page_allocator.h> |
27 | 28 | ||
@@ -34,7 +35,7 @@ void nvgpu_vidmem_destroy(struct gk20a *g) | |||
34 | nvgpu_alloc_destroy(&g->mm.vidmem.allocator); | 35 | nvgpu_alloc_destroy(&g->mm.vidmem.allocator); |
35 | } | 36 | } |
36 | 37 | ||
37 | int nvgpu_vidmem_clear_all(struct gk20a *g) | 38 | static int __nvgpu_vidmem_do_clear_all(struct gk20a *g) |
38 | { | 39 | { |
39 | struct mm_gk20a *mm = &g->mm; | 40 | struct mm_gk20a *mm = &g->mm; |
40 | struct gk20a_fence *gk20a_fence_out = NULL; | 41 | struct gk20a_fence *gk20a_fence_out = NULL; |
@@ -257,3 +258,80 @@ struct nvgpu_mem *nvgpu_vidmem_get_pending_alloc(struct mm_gk20a *mm) | |||
257 | 258 | ||
258 | return mem; | 259 | return mem; |
259 | } | 260 | } |
261 | |||
262 | static int nvgpu_vidmem_clear_all(struct gk20a *g) | ||
263 | { | ||
264 | int err; | ||
265 | |||
266 | if (g->mm.vidmem.cleared) | ||
267 | return 0; | ||
268 | |||
269 | nvgpu_mutex_acquire(&g->mm.vidmem.first_clear_mutex); | ||
270 | if (!g->mm.vidmem.cleared) { | ||
271 | err = __nvgpu_vidmem_do_clear_all(g); | ||
272 | if (err) { | ||
273 | nvgpu_mutex_release(&g->mm.vidmem.first_clear_mutex); | ||
274 | nvgpu_err(g, "failed to clear whole vidmem"); | ||
275 | return err; | ||
276 | } | ||
277 | } | ||
278 | nvgpu_mutex_release(&g->mm.vidmem.first_clear_mutex); | ||
279 | |||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | struct nvgpu_vidmem_buf *nvgpu_vidmem_user_alloc(struct gk20a *g, size_t bytes) | ||
284 | { | ||
285 | struct nvgpu_vidmem_buf *buf; | ||
286 | int err; | ||
287 | |||
288 | err = nvgpu_vidmem_clear_all(g); | ||
289 | if (err) | ||
290 | return NULL; | ||
291 | |||
292 | buf = nvgpu_kzalloc(g, sizeof(*buf)); | ||
293 | if (!buf) | ||
294 | return NULL; | ||
295 | |||
296 | buf->g = g; | ||
297 | buf->mem = nvgpu_kzalloc(g, sizeof(*buf->mem)); | ||
298 | if (!buf->mem) | ||
299 | goto fail; | ||
300 | |||
301 | err = nvgpu_dma_alloc_vid(g, bytes, buf->mem); | ||
302 | if (err) | ||
303 | goto fail; | ||
304 | |||
305 | /* | ||
306 | * Alerts the DMA API that when we free this vidmem buf we have to | ||
307 | * clear it to avoid leaking data to userspace. | ||
308 | */ | ||
309 | buf->mem->mem_flags |= NVGPU_MEM_FLAG_USER_MEM; | ||
310 | |||
311 | return buf; | ||
312 | |||
313 | fail: | ||
314 | /* buf will never be NULL here. */ | ||
315 | nvgpu_kfree(g, buf->mem); | ||
316 | nvgpu_kfree(g, buf); | ||
317 | return NULL; | ||
318 | } | ||
319 | |||
320 | void nvgpu_vidmem_buf_free(struct gk20a *g, struct nvgpu_vidmem_buf *buf) | ||
321 | { | ||
322 | /* | ||
323 | * In some error paths it's convenient to be able to "free" a NULL buf. | ||
324 | */ | ||
325 | if (!buf) | ||
326 | return; | ||
327 | |||
328 | nvgpu_dma_free(g, buf->mem); | ||
329 | |||
330 | /* | ||
331 | * We don't free buf->mem here. This is handled by nvgpu_dma_free()! | ||
332 | * Since these buffers are cleared in the background the nvgpu_mem | ||
333 | * struct must live on through that. We transfer ownership here to the | ||
334 | * DMA API and let the DMA API free the buffer. | ||
335 | */ | ||
336 | nvgpu_kfree(g, buf); | ||
337 | } | ||