summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/os/linux/vm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/os/linux/vm.c')
-rw-r--r--drivers/gpu/nvgpu/os/linux/vm.c70
1 files changed, 69 insertions, 1 deletions
diff --git a/drivers/gpu/nvgpu/os/linux/vm.c b/drivers/gpu/nvgpu/os/linux/vm.c
index 8956cce5..fcb58ac4 100644
--- a/drivers/gpu/nvgpu/os/linux/vm.c
+++ b/drivers/gpu/nvgpu/os/linux/vm.c
@@ -15,6 +15,7 @@
15 */ 15 */
16 16
17#include <linux/dma-buf.h> 17#include <linux/dma-buf.h>
18#include <linux/nvmap.h>
18#include <linux/scatterlist.h> 19#include <linux/scatterlist.h>
19#include <uapi/linux/nvgpu.h> 20#include <uapi/linux/nvgpu.h>
20 21
@@ -71,7 +72,23 @@ static struct nvgpu_mapped_buf *__nvgpu_vm_find_mapped_buf_reverse(
71{ 72{
72 struct nvgpu_rbtree_node *node = NULL; 73 struct nvgpu_rbtree_node *node = NULL;
73 struct nvgpu_rbtree_node *root = vm->mapped_buffers; 74 struct nvgpu_rbtree_node *root = vm->mapped_buffers;
75 struct list_head* nvmap_priv;
76
77 // Try fast lookup first
78 if (!IS_ERR(nvmap_priv = nvmap_get_priv_list(dmabuf))) {
79 struct nvgpu_mapped_buf *mapped_buffer;
80 struct nvgpu_mapped_buf_priv *priv;
81
82 list_for_each_entry(priv, nvmap_priv, nvmap_priv_entry) {
83 mapped_buffer = container_of(priv, struct nvgpu_mapped_buf, os_priv);
84 if (mapped_buffer->os_priv.dmabuf == dmabuf &&
85 mapped_buffer->kind == kind)
86 return mapped_buffer;
87 }
88 }
74 89
90 // Full traversal (not an nvmap buffer?)
91 printk(KERN_INFO "nvmap: Fast reverse lookup failed!");
75 nvgpu_rbtree_enum_start(0, &node, root); 92 nvgpu_rbtree_enum_start(0, &node, root);
76 93
77 while (node) { 94 while (node) {
@@ -158,6 +175,7 @@ struct nvgpu_mapped_buf *nvgpu_vm_find_mapping(struct vm_gk20a *vm,
158 */ 175 */
159 gk20a_mm_unpin(os_buf->dev, os_buf->dmabuf, os_buf->attachment, 176 gk20a_mm_unpin(os_buf->dev, os_buf->dmabuf, os_buf->attachment,
160 mapped_buffer->os_priv.sgt); 177 mapped_buffer->os_priv.sgt);
178 list_del(&mapped_buffer->os_priv.nvmap_priv_entry);
161 dma_buf_put(os_buf->dmabuf); 179 dma_buf_put(os_buf->dmabuf);
162 180
163 nvgpu_log(g, gpu_dbg_map, 181 nvgpu_log(g, gpu_dbg_map,
@@ -198,6 +216,7 @@ int nvgpu_vm_map_linux(struct vm_gk20a *vm,
198 struct nvgpu_sgt *nvgpu_sgt = NULL; 216 struct nvgpu_sgt *nvgpu_sgt = NULL;
199 struct nvgpu_mapped_buf *mapped_buffer = NULL; 217 struct nvgpu_mapped_buf *mapped_buffer = NULL;
200 struct dma_buf_attachment *attachment; 218 struct dma_buf_attachment *attachment;
219 struct list_head *nvmap_priv;
201 int err = 0; 220 int err = 0;
202 221
203 sgt = gk20a_mm_pin(dev, dmabuf, &attachment); 222 sgt = gk20a_mm_pin(dev, dmabuf, &attachment);
@@ -243,6 +262,12 @@ int nvgpu_vm_map_linux(struct vm_gk20a *vm,
243 mapped_buffer->os_priv.dmabuf = dmabuf; 262 mapped_buffer->os_priv.dmabuf = dmabuf;
244 mapped_buffer->os_priv.attachment = attachment; 263 mapped_buffer->os_priv.attachment = attachment;
245 mapped_buffer->os_priv.sgt = sgt; 264 mapped_buffer->os_priv.sgt = sgt;
265 nvmap_priv = nvmap_get_priv_list(dmabuf);
266 if (!IS_ERR(nvmap_priv))
267 list_add(&mapped_buffer->os_priv.nvmap_priv_entry, nvmap_priv);
268 else
269 // So we can always safely call list_del()
270 INIT_LIST_HEAD(&mapped_buffer->os_priv.nvmap_priv_entry);
246 271
247 *gpu_va = mapped_buffer->addr; 272 *gpu_va = mapped_buffer->addr;
248 return 0; 273 return 0;
@@ -353,6 +378,49 @@ void nvgpu_vm_unmap_system(struct nvgpu_mapped_buf *mapped_buffer)
353 gk20a_mm_unpin(dev_from_vm(vm), mapped_buffer->os_priv.dmabuf, 378 gk20a_mm_unpin(dev_from_vm(vm), mapped_buffer->os_priv.dmabuf,
354 mapped_buffer->os_priv.attachment, 379 mapped_buffer->os_priv.attachment,
355 mapped_buffer->os_priv.sgt); 380 mapped_buffer->os_priv.sgt);
356 381 list_del(&mapped_buffer->os_priv.nvmap_priv_entry);
357 dma_buf_put(mapped_buffer->os_priv.dmabuf); 382 dma_buf_put(mapped_buffer->os_priv.dmabuf);
358} 383}
384
385/**
386 * Given an nvgpu_mapped_buf m, map m->os_priv.sgt into m->addr
387 * Very similar to nvgpu_vm_map_buffer, except that this assumes all necessary
388 * PTEs and PDEs have been created. This merely updates the physical address(es)
389 * in the associated PTEs, leaving all other attributes unchanged.
390 *
391 * NOP if sgt is already mapped for addr.
392 *
393 * vm->gmmu_update_lock must be held.
394 *
395 * Caller is responsible for flushing the TLB and L2 caches.
396 */
397void nvgpu_vm_remap(struct nvgpu_mapped_buf *m)
398{
399 // TODO: Input validation
400 struct scatterlist *sg;
401 unsigned int i = 0;
402 u64 curr_vaddr = m->addr;
403
404 // For each element of the scatterlist
405 // (based off for_each_sgtable_dma_sg() macro in newer kernels)
406 for_each_sg(m->os_priv.sgt->sgl, sg, m->os_priv.sgt->nents, i) {
407 unsigned int sg_off = 0;
408 // Keep mapping data at the next unmapped virtual address
409 // until each scatterlist element is entirely mapped
410 while (sg_off < sg_dma_len(sg)) {
411 int amt_mapped = __nvgpu_update_paddr(gk20a_from_vm(m->vm),
412 m->vm,
413 curr_vaddr,
414 sg_dma_address(sg) + sg_off);
415 if (amt_mapped < 0) {
416 printk(KERN_ERR "nvgpu: Error %d from __nvgpu_update_paddr() in nvgpu_vm_remap()! Had mapped %llu of %llu bytes.\n", amt_mapped, curr_vaddr - m->addr, m->size);
417 return;
418 }
419 curr_vaddr += amt_mapped;
420 sg_off += amt_mapped;
421 }
422 }
423 if (curr_vaddr != m->addr + m->size) {
424 printk(KERN_ERR "nvgpu: Mapped %llu bytes when %llu bytes expected! Expect page table corruption!\n", curr_vaddr - m->addr, m->size);
425 }
426}