summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/common/linux/vm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/common/linux/vm.c')
-rw-r--r--drivers/gpu/nvgpu/common/linux/vm.c202
1 files changed, 201 insertions, 1 deletions
diff --git a/drivers/gpu/nvgpu/common/linux/vm.c b/drivers/gpu/nvgpu/common/linux/vm.c
index b686d616..638d3e51 100644
--- a/drivers/gpu/nvgpu/common/linux/vm.c
+++ b/drivers/gpu/nvgpu/common/linux/vm.c
@@ -115,6 +115,108 @@ static u64 nvgpu_get_buffer_alignment(struct gk20a *g, struct scatterlist *sgl,
115 return align; 115 return align;
116} 116}
117 117
118static int setup_kind_legacy(struct vm_gk20a *vm, struct buffer_attrs *bfr,
119 bool *pkind_compressible)
120{
121 struct gk20a *g = gk20a_from_vm(vm);
122 bool kind_compressible;
123
124 if (unlikely(bfr->kind_v == g->ops.mm.get_kind_invalid()))
125 bfr->kind_v = g->ops.mm.get_kind_pitch();
126
127 if (unlikely(!gk20a_kind_is_supported(bfr->kind_v))) {
128 nvgpu_err(g, "kind 0x%x not supported", bfr->kind_v);
129 return -EINVAL;
130 }
131
132 bfr->uc_kind_v = g->ops.mm.get_kind_invalid();
133 /* find a suitable incompressible kind if it becomes necessary later */
134 kind_compressible = gk20a_kind_is_compressible(bfr->kind_v);
135 if (kind_compressible) {
136 bfr->uc_kind_v = gk20a_get_uncompressed_kind(bfr->kind_v);
137 if (unlikely(bfr->uc_kind_v == g->ops.mm.get_kind_invalid())) {
138 /* shouldn't happen, but it is worth cross-checking */
139 nvgpu_err(g, "comptag kind 0x%x can't be"
140 " downgraded to uncompressed kind",
141 bfr->kind_v);
142 return -EINVAL;
143 }
144 }
145
146 *pkind_compressible = kind_compressible;
147 return 0;
148}
149
150static int setup_buffer_kind_and_compression(struct vm_gk20a *vm,
151 u32 flags,
152 struct buffer_attrs *bfr,
153 enum gmmu_pgsz_gk20a pgsz_idx)
154{
155 bool kind_compressible;
156 struct gk20a *g = gk20a_from_vm(vm);
157 int ctag_granularity = g->ops.fb.compression_page_size(g);
158
159 if (!bfr->use_kind_v)
160 bfr->kind_v = g->ops.mm.get_kind_invalid();
161 if (!bfr->use_uc_kind_v)
162 bfr->uc_kind_v = g->ops.mm.get_kind_invalid();
163
164 if (flags & NVGPU_AS_MAP_BUFFER_FLAGS_DIRECT_KIND_CTRL) {
165 kind_compressible = (bfr->kind_v !=
166 g->ops.mm.get_kind_invalid());
167 if (!kind_compressible)
168 bfr->kind_v = bfr->uc_kind_v;
169 } else {
170 int err = setup_kind_legacy(vm, bfr, &kind_compressible);
171
172 if (err)
173 return err;
174 }
175
176 /* comptags only supported for suitable kinds, 128KB pagesize */
177 if (kind_compressible &&
178 vm->gmmu_page_sizes[pgsz_idx] <
179 g->ops.fb.compressible_page_size(g)) {
180 /* it is safe to fall back to uncompressed as
181 functionality is not harmed */
182 bfr->kind_v = bfr->uc_kind_v;
183 kind_compressible = false;
184 }
185 if (kind_compressible)
186 bfr->ctag_lines = DIV_ROUND_UP_ULL(bfr->size, ctag_granularity);
187 else
188 bfr->ctag_lines = 0;
189
190 bfr->use_kind_v = (bfr->kind_v != g->ops.mm.get_kind_invalid());
191 bfr->use_uc_kind_v = (bfr->uc_kind_v != g->ops.mm.get_kind_invalid());
192
193 return 0;
194}
195
196int nvgpu_vm_find_buf(struct vm_gk20a *vm, u64 gpu_va,
197 struct dma_buf **dmabuf,
198 u64 *offset)
199{
200 struct nvgpu_mapped_buf *mapped_buffer;
201
202 gk20a_dbg_fn("gpu_va=0x%llx", gpu_va);
203
204 nvgpu_mutex_acquire(&vm->update_gmmu_lock);
205
206 mapped_buffer = __nvgpu_vm_find_mapped_buf_range(vm, gpu_va);
207 if (!mapped_buffer) {
208 nvgpu_mutex_release(&vm->update_gmmu_lock);
209 return -EINVAL;
210 }
211
212 *dmabuf = mapped_buffer->dmabuf;
213 *offset = gpu_va - mapped_buffer->addr;
214
215 nvgpu_mutex_release(&vm->update_gmmu_lock);
216
217 return 0;
218}
219
118/* 220/*
119 * vm->update_gmmu_lock must be held. This checks to see if we already have 221 * vm->update_gmmu_lock must be held. This checks to see if we already have
120 * mapped the passed buffer into this VM. If so, just return the existing 222 * mapped the passed buffer into this VM. If so, just return the existing
@@ -478,6 +580,67 @@ clean_up:
478 return 0; 580 return 0;
479} 581}
480 582
583int nvgpu_vm_map_buffer(struct vm_gk20a *vm,
584 int dmabuf_fd,
585 u64 *offset_align,
586 u32 flags, /*NVGPU_AS_MAP_BUFFER_FLAGS_*/
587 s16 compr_kind,
588 s16 incompr_kind,
589 u64 buffer_offset,
590 u64 mapping_size,
591 struct vm_gk20a_mapping_batch *batch)
592{
593 int err = 0;
594 struct dma_buf *dmabuf;
595 u64 ret_va;
596
597 gk20a_dbg_fn("");
598
599 /* get ref to the mem handle (released on unmap_locked) */
600 dmabuf = dma_buf_get(dmabuf_fd);
601 if (IS_ERR(dmabuf)) {
602 nvgpu_warn(gk20a_from_vm(vm), "%s: fd %d is not a dmabuf",
603 __func__, dmabuf_fd);
604 return PTR_ERR(dmabuf);
605 }
606
607 /* verify that we're not overflowing the buffer, i.e.
608 * (buffer_offset + mapping_size)> dmabuf->size.
609 *
610 * Since buffer_offset + mapping_size could overflow, first check
611 * that mapping size < dmabuf_size, at which point we can subtract
612 * mapping_size from both sides for the final comparison.
613 */
614 if ((mapping_size > dmabuf->size) ||
615 (buffer_offset > (dmabuf->size - mapping_size))) {
616 nvgpu_err(gk20a_from_vm(vm),
617 "buf size %llx < (offset(%llx) + map_size(%llx))\n",
618 (u64)dmabuf->size, buffer_offset, mapping_size);
619 return -EINVAL;
620 }
621
622 err = gk20a_dmabuf_alloc_drvdata(dmabuf, dev_from_vm(vm));
623 if (err) {
624 dma_buf_put(dmabuf);
625 return err;
626 }
627
628 ret_va = nvgpu_vm_map(vm, dmabuf, *offset_align,
629 flags, compr_kind, incompr_kind, true,
630 gk20a_mem_flag_none,
631 buffer_offset,
632 mapping_size,
633 batch);
634
635 *offset_align = ret_va;
636 if (!ret_va) {
637 dma_buf_put(dmabuf);
638 err = -EINVAL;
639 }
640
641 return err;
642}
643
481void nvgpu_vm_unmap(struct vm_gk20a *vm, u64 offset) 644void nvgpu_vm_unmap(struct vm_gk20a *vm, u64 offset)
482{ 645{
483 struct gk20a *g = vm->mm->g; 646 struct gk20a *g = vm->mm->g;
@@ -491,6 +654,43 @@ void nvgpu_vm_unmap(struct vm_gk20a *vm, u64 offset)
491 return; 654 return;
492 } 655 }
493 656
494 nvgpu_ref_put(&mapped_buffer->ref, gk20a_vm_unmap_locked_ref); 657 nvgpu_ref_put(&mapped_buffer->ref, nvgpu_vm_unmap_locked_ref);
495 nvgpu_mutex_release(&vm->update_gmmu_lock); 658 nvgpu_mutex_release(&vm->update_gmmu_lock);
496} 659}
660
661/* NOTE! mapped_buffers lock must be held */
662void nvgpu_vm_unmap_locked(struct nvgpu_mapped_buf *mapped_buffer,
663 struct vm_gk20a_mapping_batch *batch)
664{
665 struct vm_gk20a *vm = mapped_buffer->vm;
666 struct gk20a *g = vm->mm->g;
667
668 g->ops.mm.gmmu_unmap(vm,
669 mapped_buffer->addr,
670 mapped_buffer->size,
671 mapped_buffer->pgsz_idx,
672 mapped_buffer->va_allocated,
673 gk20a_mem_flag_none,
674 mapped_buffer->vm_area ?
675 mapped_buffer->vm_area->sparse : false,
676 batch);
677
678 gk20a_mm_unpin(dev_from_vm(vm), mapped_buffer->dmabuf,
679 mapped_buffer->sgt);
680
681 /* remove from mapped buffer tree and remove list, free */
682 nvgpu_remove_mapped_buf(vm, mapped_buffer);
683 if (!nvgpu_list_empty(&mapped_buffer->buffer_list))
684 nvgpu_list_del(&mapped_buffer->buffer_list);
685
686 /* keep track of mapped buffers */
687 if (mapped_buffer->user_mapped)
688 vm->num_user_mapped_buffers--;
689
690 if (mapped_buffer->own_mem_ref)
691 dma_buf_put(mapped_buffer->dmabuf);
692
693 nvgpu_kfree(g, mapped_buffer);
694
695 return;
696}