diff options
Diffstat (limited to 'drivers/gpu/nvgpu/os/linux/vm.c')
-rw-r--r-- | drivers/gpu/nvgpu/os/linux/vm.c | 70 |
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 | */ | ||
397 | void 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 | } | ||