diff options
author | Niranjana Vishwanathapura <niranjana.vishwanathapura@intel.com> | 2022-07-01 15:50:47 -0700 |
---|---|---|
committer | Andi Shyti <andi.shyti@linux.intel.com> | 2022-07-27 14:01:26 +0000 |
commit | 4d69cd8e3f92fe08b300a1e7868fc1c882b5fc78 (patch) | |
tree | 1d0ef7412621aaa3d76bee0d06242634f4342e2c /drivers/gpu/drm/i915/gem/i915_gem_vm_bind_object.c | |
parent | 7592cf2fb881100b14547d14a245ae9ea59761f5 (diff) |
drm/i915/vm_bind: Bind and unbind mappings
Bind and unbind the mappings upon VM_BIND and VM_UNBIND calls.
Signed-off-by: Niranjana Vishwanathapura <niranjana.vishwanathapura@intel.com>
Signed-off-by: Prathap Kumar Valsan <prathap.kumar.valsan@intel.com>
Diffstat (limited to 'drivers/gpu/drm/i915/gem/i915_gem_vm_bind_object.c')
-rw-r--r-- | drivers/gpu/drm/i915/gem/i915_gem_vm_bind_object.c | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_vm_bind_object.c b/drivers/gpu/drm/i915/gem/i915_gem_vm_bind_object.c new file mode 100644 index 000000000000..43ceb4dcca6c --- /dev/null +++ b/drivers/gpu/drm/i915/gem/i915_gem_vm_bind_object.c @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2022 Intel Corporation + */ + +#include <linux/interval_tree_generic.h> + +#include "gem/i915_gem_vm_bind.h" +#include "gt/gen8_engine_cs.h" + +#include "i915_drv.h" +#include "i915_gem_gtt.h" + +#define START(node) ((node)->start) +#define LAST(node) ((node)->last) + +INTERVAL_TREE_DEFINE(struct i915_vma, rb, u64, __subtree_last, + START, LAST, static inline, i915_vm_bind_it) + +#undef START +#undef LAST + +/** + * DOC: VM_BIND/UNBIND ioctls + * + * DRM_I915_GEM_VM_BIND/UNBIND ioctls allows UMD to bind/unbind GEM buffer + * objects (BOs) or sections of a BOs at specified GPU virtual addresses on a + * specified address space (VM). Multiple mappings can map to the same physical + * pages of an object (aliasing). These mappings (also referred to as persistent + * mappings) will be persistent across multiple GPU submissions (execbuf calls) + * issued by the UMD, without user having to provide a list of all required + * mappings during each submission (as required by older execbuf mode). + * + * The VM_BIND/UNBIND calls allow UMDs to request a timeline out fence for + * signaling the completion of bind/unbind operation. + * + * VM_BIND feature is advertised to user via I915_PARAM_VM_BIND_VERSION. + * User has to opt-in for VM_BIND mode of binding for an address space (VM) + * during VM creation time via I915_VM_CREATE_FLAGS_USE_VM_BIND extension. + * + * VM_BIND/UNBIND ioctl calls executed on different CPU threads concurrently + * are not ordered. Furthermore, parts of the VM_BIND/UNBIND operations can be + * done asynchronously, when valid out fence is specified. + * + * VM_BIND locking order is as below. + * + * 1) Lock-A: A vm_bind mutex will protect vm_bind lists. This lock is taken in + * vm_bind/vm_unbind ioctl calls, in the execbuf path and while releasing the + * mapping. + * + * In future, when GPU page faults are supported, we can potentially use a + * rwsem instead, so that multiple page fault handlers can take the read + * side lock to lookup the mapping and hence can run in parallel. + * The older execbuf mode of binding do not need this lock. + * + * 2) Lock-B: The object's dma-resv lock will protect i915_vma state and needs + * to be held while binding/unbinding a vma in the async worker and while + * updating dma-resv fence list of an object. Note that private BOs of a VM + * will all share a dma-resv object. + * + * The future system allocator support will use the HMM prescribed locking + * instead. + * + * 3) Lock-C: Spinlock/s to protect some of the VM's lists like the list of + * invalidated vmas (due to eviction and userptr invalidation) etc. + */ + +struct i915_vma * +i915_gem_vm_bind_lookup_vma(struct i915_address_space *vm, u64 va) +{ + struct i915_vma *vma, *temp; + + assert_vm_bind_held(vm); + + vma = i915_vm_bind_it_iter_first(&vm->va, va, va); + /* Working around compiler error, remove later */ + if (vma) + temp = i915_vm_bind_it_iter_next(vma, va + vma->size, -1); + return vma; +} + +void i915_gem_vm_bind_remove(struct i915_vma *vma, bool release_obj) +{ + assert_vm_bind_held(vma->vm); + + if (!list_empty(&vma->vm_bind_link)) { + list_del_init(&vma->vm_bind_link); + i915_vm_bind_it_remove(vma, &vma->vm->va); + + /* Release object */ + if (release_obj) + i915_vma_put(vma); + } +} + +int i915_gem_vm_unbind_obj(struct i915_address_space *vm, + struct drm_i915_gem_vm_unbind *va) +{ + struct drm_i915_gem_object *obj; + struct i915_vma *vma; + int ret; + + va->start = gen8_noncanonical_addr(va->start); + ret = i915_gem_vm_bind_lock_interruptible(vm); + if (ret) + return ret; + + vma = i915_gem_vm_bind_lookup_vma(vm, va->start); + if (!vma) { + ret = -ENOENT; + goto out_unlock; + } + + if (vma->size != va->length) + ret = -EINVAL; + else + i915_gem_vm_bind_remove(vma, false); + +out_unlock: + i915_gem_vm_bind_unlock(vm); + if (ret || !vma) + return ret; + + /* Destroy vma and then release object */ + obj = vma->obj; + ret = i915_gem_object_lock(obj, NULL); + if (ret) + return ret; + + i915_vma_destroy(vma); + i915_gem_object_unlock(obj); + i915_gem_object_put(obj); + + return 0; +} + +static struct i915_vma *vm_bind_get_vma(struct i915_address_space *vm, + struct drm_i915_gem_object *obj, + struct drm_i915_gem_vm_bind *va) +{ + struct i915_ggtt_view view; + struct i915_vma *vma; + + va->start = gen8_noncanonical_addr(va->start); + vma = i915_gem_vm_bind_lookup_vma(vm, va->start); + if (vma) + return ERR_PTR(-EEXIST); + + view.type = I915_GGTT_VIEW_PARTIAL; + view.partial.offset = va->offset >> PAGE_SHIFT; + view.partial.size = va->length >> PAGE_SHIFT; + vma = i915_vma_instance(obj, vm, &view); + if (IS_ERR(vma)) + return vma; + + vma->start = va->start; + vma->last = va->start + va->length - 1; + + return vma; +} + +int i915_gem_vm_bind_obj(struct i915_address_space *vm, + struct drm_i915_gem_vm_bind *va, + struct drm_file *file) +{ + struct drm_i915_gem_object *obj; + struct i915_vma *vma = NULL; + struct i915_gem_ww_ctx ww; + u64 pin_flags; + int ret = 0; + + if (!vm->vm_bind_mode) + return -EOPNOTSUPP; + + obj = i915_gem_object_lookup(file, va->handle); + if (!obj) + return -ENOENT; + + if (!va->length || + !IS_ALIGNED(va->offset | va->length, + i915_gem_object_max_page_size(obj->mm.placements, + obj->mm.n_placements)) || + range_overflows_t(u64, va->offset, va->length, obj->base.size)) { + ret = -EINVAL; + goto put_obj; + } + + ret = i915_gem_vm_bind_lock_interruptible(vm); + if (ret) + goto put_obj; + + vma = vm_bind_get_vma(vm, obj, va); + if (IS_ERR(vma)) { + ret = PTR_ERR(vma); + goto unlock_vm; + } + + i915_gem_ww_ctx_init(&ww, true); + pin_flags = va->start | PIN_OFFSET_FIXED | PIN_USER; +retry: + ret = i915_gem_object_lock(vma->obj, &ww); + if (ret) + goto out_ww; + + ret = i915_vma_pin_ww(vma, &ww, 0, 0, pin_flags); + if (ret) + goto out_ww; + + /* Make it evictable */ + __i915_vma_unpin(vma); + + list_add_tail(&vma->vm_bind_link, &vm->vm_bound_list); + i915_vm_bind_it_insert(vma, &vm->va); + + /* Hold object reference until vm_unbind */ + i915_gem_object_get(vma->obj); +out_ww: + if (ret == -EDEADLK) { + ret = i915_gem_ww_ctx_backoff(&ww); + if (!ret) + goto retry; + } + + if (ret) + i915_vma_destroy(vma); + + i915_gem_ww_ctx_fini(&ww); +unlock_vm: + i915_gem_vm_bind_unlock(vm); +put_obj: + i915_gem_object_put(obj); + return ret; +} |