162306a36Sopenharmony_ci// SPDX-License-Identifier: MIT 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright © 2021 Intel Corporation 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/interval_tree_generic.h> 762306a36Sopenharmony_ci#include <linux/sched/mm.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "i915_sw_fence.h" 1062306a36Sopenharmony_ci#include "i915_vma_resource.h" 1162306a36Sopenharmony_ci#include "i915_drv.h" 1262306a36Sopenharmony_ci#include "intel_memory_region.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "gt/intel_gtt.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic struct kmem_cache *slab_vma_resources; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/** 1962306a36Sopenharmony_ci * DOC: 2062306a36Sopenharmony_ci * We use a per-vm interval tree to keep track of vma_resources 2162306a36Sopenharmony_ci * scheduled for unbind but not yet unbound. The tree is protected by 2262306a36Sopenharmony_ci * the vm mutex, and nodes are removed just after the unbind fence signals. 2362306a36Sopenharmony_ci * The removal takes the vm mutex from a kernel thread which we need to 2462306a36Sopenharmony_ci * keep in mind so that we don't grab the mutex and try to wait for all 2562306a36Sopenharmony_ci * pending unbinds to complete, because that will temporaryily block many 2662306a36Sopenharmony_ci * of the workqueue threads, and people will get angry. 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci * We should consider using a single ordered fence per VM instead but that 2962306a36Sopenharmony_ci * requires ordering the unbinds and might introduce unnecessary waiting 3062306a36Sopenharmony_ci * for unrelated unbinds. Amount of code will probably be roughly the same 3162306a36Sopenharmony_ci * due to the simplicity of using the interval tree interface. 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * Another drawback of this interval tree is that the complexity of insertion 3462306a36Sopenharmony_ci * and removal of fences increases as O(ln(pending_unbinds)) instead of 3562306a36Sopenharmony_ci * O(1) for a single fence without interval tree. 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_ci#define VMA_RES_START(_node) ((_node)->start - (_node)->guard) 3862306a36Sopenharmony_ci#define VMA_RES_LAST(_node) ((_node)->start + (_node)->node_size + (_node)->guard - 1) 3962306a36Sopenharmony_ciINTERVAL_TREE_DEFINE(struct i915_vma_resource, rb, 4062306a36Sopenharmony_ci u64, __subtree_last, 4162306a36Sopenharmony_ci VMA_RES_START, VMA_RES_LAST, static, vma_res_itree); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* Callbacks for the unbind dma-fence. */ 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/** 4662306a36Sopenharmony_ci * i915_vma_resource_alloc - Allocate a vma resource 4762306a36Sopenharmony_ci * 4862306a36Sopenharmony_ci * Return: A pointer to a cleared struct i915_vma_resource or 4962306a36Sopenharmony_ci * a -ENOMEM error pointer if allocation fails. 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_cistruct i915_vma_resource *i915_vma_resource_alloc(void) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci struct i915_vma_resource *vma_res = 5462306a36Sopenharmony_ci kmem_cache_zalloc(slab_vma_resources, GFP_KERNEL); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci return vma_res ? vma_res : ERR_PTR(-ENOMEM); 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/** 6062306a36Sopenharmony_ci * i915_vma_resource_free - Free a vma resource 6162306a36Sopenharmony_ci * @vma_res: The vma resource to free. 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_civoid i915_vma_resource_free(struct i915_vma_resource *vma_res) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci if (vma_res) 6662306a36Sopenharmony_ci kmem_cache_free(slab_vma_resources, vma_res); 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic const char *get_driver_name(struct dma_fence *fence) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci return "vma unbind fence"; 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic const char *get_timeline_name(struct dma_fence *fence) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci return "unbound"; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic void unbind_fence_free_rcu(struct rcu_head *head) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci struct i915_vma_resource *vma_res = 8262306a36Sopenharmony_ci container_of(head, typeof(*vma_res), unbind_fence.rcu); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci i915_vma_resource_free(vma_res); 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic void unbind_fence_release(struct dma_fence *fence) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci struct i915_vma_resource *vma_res = 9062306a36Sopenharmony_ci container_of(fence, typeof(*vma_res), unbind_fence); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci i915_sw_fence_fini(&vma_res->chain); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci call_rcu(&fence->rcu, unbind_fence_free_rcu); 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic struct dma_fence_ops unbind_fence_ops = { 9862306a36Sopenharmony_ci .get_driver_name = get_driver_name, 9962306a36Sopenharmony_ci .get_timeline_name = get_timeline_name, 10062306a36Sopenharmony_ci .release = unbind_fence_release, 10162306a36Sopenharmony_ci}; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic void __i915_vma_resource_unhold(struct i915_vma_resource *vma_res) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci struct i915_address_space *vm; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci if (!refcount_dec_and_test(&vma_res->hold_count)) 10862306a36Sopenharmony_ci return; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci dma_fence_signal(&vma_res->unbind_fence); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci vm = vma_res->vm; 11362306a36Sopenharmony_ci if (vma_res->wakeref) 11462306a36Sopenharmony_ci intel_runtime_pm_put(&vm->i915->runtime_pm, vma_res->wakeref); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci vma_res->vm = NULL; 11762306a36Sopenharmony_ci if (!RB_EMPTY_NODE(&vma_res->rb)) { 11862306a36Sopenharmony_ci mutex_lock(&vm->mutex); 11962306a36Sopenharmony_ci vma_res_itree_remove(vma_res, &vm->pending_unbind); 12062306a36Sopenharmony_ci mutex_unlock(&vm->mutex); 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (vma_res->bi.pages_rsgt) 12462306a36Sopenharmony_ci i915_refct_sgt_put(vma_res->bi.pages_rsgt); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci/** 12862306a36Sopenharmony_ci * i915_vma_resource_unhold - Unhold the signaling of the vma resource unbind 12962306a36Sopenharmony_ci * fence. 13062306a36Sopenharmony_ci * @vma_res: The vma resource. 13162306a36Sopenharmony_ci * @lockdep_cookie: The lockdep cookie returned from i915_vma_resource_hold. 13262306a36Sopenharmony_ci * 13362306a36Sopenharmony_ci * The function may leave a dma_fence critical section. 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_civoid i915_vma_resource_unhold(struct i915_vma_resource *vma_res, 13662306a36Sopenharmony_ci bool lockdep_cookie) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci dma_fence_end_signalling(lockdep_cookie); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_PROVE_LOCKING)) { 14162306a36Sopenharmony_ci unsigned long irq_flags; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /* Inefficient open-coded might_lock_irqsave() */ 14462306a36Sopenharmony_ci spin_lock_irqsave(&vma_res->lock, irq_flags); 14562306a36Sopenharmony_ci spin_unlock_irqrestore(&vma_res->lock, irq_flags); 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci __i915_vma_resource_unhold(vma_res); 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci/** 15262306a36Sopenharmony_ci * i915_vma_resource_hold - Hold the signaling of the vma resource unbind fence. 15362306a36Sopenharmony_ci * @vma_res: The vma resource. 15462306a36Sopenharmony_ci * @lockdep_cookie: Pointer to a bool serving as a lockdep cooke that should 15562306a36Sopenharmony_ci * be given as an argument to the pairing i915_vma_resource_unhold. 15662306a36Sopenharmony_ci * 15762306a36Sopenharmony_ci * If returning true, the function enters a dma_fence signalling critical 15862306a36Sopenharmony_ci * section if not in one already. 15962306a36Sopenharmony_ci * 16062306a36Sopenharmony_ci * Return: true if holding successful, false if not. 16162306a36Sopenharmony_ci */ 16262306a36Sopenharmony_cibool i915_vma_resource_hold(struct i915_vma_resource *vma_res, 16362306a36Sopenharmony_ci bool *lockdep_cookie) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci bool held = refcount_inc_not_zero(&vma_res->hold_count); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (held) 16862306a36Sopenharmony_ci *lockdep_cookie = dma_fence_begin_signalling(); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci return held; 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic void i915_vma_resource_unbind_work(struct work_struct *work) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci struct i915_vma_resource *vma_res = 17662306a36Sopenharmony_ci container_of(work, typeof(*vma_res), work); 17762306a36Sopenharmony_ci struct i915_address_space *vm = vma_res->vm; 17862306a36Sopenharmony_ci bool lockdep_cookie; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci lockdep_cookie = dma_fence_begin_signalling(); 18162306a36Sopenharmony_ci if (likely(!vma_res->skip_pte_rewrite)) 18262306a36Sopenharmony_ci vma_res->ops->unbind_vma(vm, vma_res); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci dma_fence_end_signalling(lockdep_cookie); 18562306a36Sopenharmony_ci __i915_vma_resource_unhold(vma_res); 18662306a36Sopenharmony_ci i915_vma_resource_put(vma_res); 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic int 19062306a36Sopenharmony_cii915_vma_resource_fence_notify(struct i915_sw_fence *fence, 19162306a36Sopenharmony_ci enum i915_sw_fence_notify state) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci struct i915_vma_resource *vma_res = 19462306a36Sopenharmony_ci container_of(fence, typeof(*vma_res), chain); 19562306a36Sopenharmony_ci struct dma_fence *unbind_fence = 19662306a36Sopenharmony_ci &vma_res->unbind_fence; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci switch (state) { 19962306a36Sopenharmony_ci case FENCE_COMPLETE: 20062306a36Sopenharmony_ci dma_fence_get(unbind_fence); 20162306a36Sopenharmony_ci if (vma_res->immediate_unbind) { 20262306a36Sopenharmony_ci i915_vma_resource_unbind_work(&vma_res->work); 20362306a36Sopenharmony_ci } else { 20462306a36Sopenharmony_ci INIT_WORK(&vma_res->work, i915_vma_resource_unbind_work); 20562306a36Sopenharmony_ci queue_work(system_unbound_wq, &vma_res->work); 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci break; 20862306a36Sopenharmony_ci case FENCE_FREE: 20962306a36Sopenharmony_ci i915_vma_resource_put(vma_res); 21062306a36Sopenharmony_ci break; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci return NOTIFY_DONE; 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci/** 21762306a36Sopenharmony_ci * i915_vma_resource_unbind - Unbind a vma resource 21862306a36Sopenharmony_ci * @vma_res: The vma resource to unbind. 21962306a36Sopenharmony_ci * @tlb: pointer to vma->obj->mm.tlb associated with the resource 22062306a36Sopenharmony_ci * to be stored at vma_res->tlb. When not-NULL, it will be used 22162306a36Sopenharmony_ci * to do TLB cache invalidation before freeing a VMA resource. 22262306a36Sopenharmony_ci * Used only for async unbind. 22362306a36Sopenharmony_ci * 22462306a36Sopenharmony_ci * At this point this function does little more than publish a fence that 22562306a36Sopenharmony_ci * signals immediately unless signaling is held back. 22662306a36Sopenharmony_ci * 22762306a36Sopenharmony_ci * Return: A refcounted pointer to a dma-fence that signals when unbinding is 22862306a36Sopenharmony_ci * complete. 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_cistruct dma_fence *i915_vma_resource_unbind(struct i915_vma_resource *vma_res, 23162306a36Sopenharmony_ci u32 *tlb) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci struct i915_address_space *vm = vma_res->vm; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci vma_res->tlb = tlb; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* Reference for the sw fence */ 23862306a36Sopenharmony_ci i915_vma_resource_get(vma_res); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci /* Caller must already have a wakeref in this case. */ 24162306a36Sopenharmony_ci if (vma_res->needs_wakeref) 24262306a36Sopenharmony_ci vma_res->wakeref = intel_runtime_pm_get_if_in_use(&vm->i915->runtime_pm); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci if (atomic_read(&vma_res->chain.pending) <= 1) { 24562306a36Sopenharmony_ci RB_CLEAR_NODE(&vma_res->rb); 24662306a36Sopenharmony_ci vma_res->immediate_unbind = 1; 24762306a36Sopenharmony_ci } else { 24862306a36Sopenharmony_ci vma_res_itree_insert(vma_res, &vma_res->vm->pending_unbind); 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci i915_sw_fence_commit(&vma_res->chain); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci return &vma_res->unbind_fence; 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci/** 25762306a36Sopenharmony_ci * __i915_vma_resource_init - Initialize a vma resource. 25862306a36Sopenharmony_ci * @vma_res: The vma resource to initialize 25962306a36Sopenharmony_ci * 26062306a36Sopenharmony_ci * Initializes the private members of a vma resource. 26162306a36Sopenharmony_ci */ 26262306a36Sopenharmony_civoid __i915_vma_resource_init(struct i915_vma_resource *vma_res) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci spin_lock_init(&vma_res->lock); 26562306a36Sopenharmony_ci dma_fence_init(&vma_res->unbind_fence, &unbind_fence_ops, 26662306a36Sopenharmony_ci &vma_res->lock, 0, 0); 26762306a36Sopenharmony_ci refcount_set(&vma_res->hold_count, 1); 26862306a36Sopenharmony_ci i915_sw_fence_init(&vma_res->chain, i915_vma_resource_fence_notify); 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic void 27262306a36Sopenharmony_cii915_vma_resource_color_adjust_range(struct i915_address_space *vm, 27362306a36Sopenharmony_ci u64 *start, 27462306a36Sopenharmony_ci u64 *end) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci if (i915_vm_has_cache_coloring(vm)) { 27762306a36Sopenharmony_ci if (*start) 27862306a36Sopenharmony_ci *start -= I915_GTT_PAGE_SIZE; 27962306a36Sopenharmony_ci *end += I915_GTT_PAGE_SIZE; 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci/** 28462306a36Sopenharmony_ci * i915_vma_resource_bind_dep_sync - Wait for / sync all unbinds touching a 28562306a36Sopenharmony_ci * certain vm range. 28662306a36Sopenharmony_ci * @vm: The vm to look at. 28762306a36Sopenharmony_ci * @offset: The range start. 28862306a36Sopenharmony_ci * @size: The range size. 28962306a36Sopenharmony_ci * @intr: Whether to wait interrubtible. 29062306a36Sopenharmony_ci * 29162306a36Sopenharmony_ci * The function needs to be called with the vm lock held. 29262306a36Sopenharmony_ci * 29362306a36Sopenharmony_ci * Return: Zero on success, -ERESTARTSYS if interrupted and @intr==true 29462306a36Sopenharmony_ci */ 29562306a36Sopenharmony_ciint i915_vma_resource_bind_dep_sync(struct i915_address_space *vm, 29662306a36Sopenharmony_ci u64 offset, 29762306a36Sopenharmony_ci u64 size, 29862306a36Sopenharmony_ci bool intr) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci struct i915_vma_resource *node; 30162306a36Sopenharmony_ci u64 last = offset + size - 1; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci lockdep_assert_held(&vm->mutex); 30462306a36Sopenharmony_ci might_sleep(); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci i915_vma_resource_color_adjust_range(vm, &offset, &last); 30762306a36Sopenharmony_ci node = vma_res_itree_iter_first(&vm->pending_unbind, offset, last); 30862306a36Sopenharmony_ci while (node) { 30962306a36Sopenharmony_ci int ret = dma_fence_wait(&node->unbind_fence, intr); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (ret) 31262306a36Sopenharmony_ci return ret; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci node = vma_res_itree_iter_next(node, offset, last); 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci return 0; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci/** 32162306a36Sopenharmony_ci * i915_vma_resource_bind_dep_sync_all - Wait for / sync all unbinds of a vm, 32262306a36Sopenharmony_ci * releasing the vm lock while waiting. 32362306a36Sopenharmony_ci * @vm: The vm to look at. 32462306a36Sopenharmony_ci * 32562306a36Sopenharmony_ci * The function may not be called with the vm lock held. 32662306a36Sopenharmony_ci * Typically this is called at vm destruction to finish any pending 32762306a36Sopenharmony_ci * unbind operations. The vm mutex is released while waiting to avoid 32862306a36Sopenharmony_ci * stalling kernel workqueues trying to grab the mutex. 32962306a36Sopenharmony_ci */ 33062306a36Sopenharmony_civoid i915_vma_resource_bind_dep_sync_all(struct i915_address_space *vm) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci struct i915_vma_resource *node; 33362306a36Sopenharmony_ci struct dma_fence *fence; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci do { 33662306a36Sopenharmony_ci fence = NULL; 33762306a36Sopenharmony_ci mutex_lock(&vm->mutex); 33862306a36Sopenharmony_ci node = vma_res_itree_iter_first(&vm->pending_unbind, 0, 33962306a36Sopenharmony_ci U64_MAX); 34062306a36Sopenharmony_ci if (node) 34162306a36Sopenharmony_ci fence = dma_fence_get_rcu(&node->unbind_fence); 34262306a36Sopenharmony_ci mutex_unlock(&vm->mutex); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (fence) { 34562306a36Sopenharmony_ci /* 34662306a36Sopenharmony_ci * The wait makes sure the node eventually removes 34762306a36Sopenharmony_ci * itself from the tree. 34862306a36Sopenharmony_ci */ 34962306a36Sopenharmony_ci dma_fence_wait(fence, false); 35062306a36Sopenharmony_ci dma_fence_put(fence); 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci } while (node); 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci/** 35662306a36Sopenharmony_ci * i915_vma_resource_bind_dep_await - Have a struct i915_sw_fence await all 35762306a36Sopenharmony_ci * pending unbinds in a certain range of a vm. 35862306a36Sopenharmony_ci * @vm: The vm to look at. 35962306a36Sopenharmony_ci * @sw_fence: The struct i915_sw_fence that will be awaiting the unbinds. 36062306a36Sopenharmony_ci * @offset: The range start. 36162306a36Sopenharmony_ci * @size: The range size. 36262306a36Sopenharmony_ci * @intr: Whether to wait interrubtible. 36362306a36Sopenharmony_ci * @gfp: Allocation mode for memory allocations. 36462306a36Sopenharmony_ci * 36562306a36Sopenharmony_ci * The function makes @sw_fence await all pending unbinds in a certain 36662306a36Sopenharmony_ci * vm range before calling the complete notifier. To be able to await 36762306a36Sopenharmony_ci * each individual unbind, the function needs to allocate memory using 36862306a36Sopenharmony_ci * the @gpf allocation mode. If that fails, the function will instead 36962306a36Sopenharmony_ci * wait for the unbind fence to signal, using @intr to judge whether to 37062306a36Sopenharmony_ci * wait interruptible or not. Note that @gfp should ideally be selected so 37162306a36Sopenharmony_ci * as to avoid any expensive memory allocation stalls and rather fail and 37262306a36Sopenharmony_ci * synchronize itself. For now the vm mutex is required when calling this 37362306a36Sopenharmony_ci * function with means that @gfp can't call into direct reclaim. In reality 37462306a36Sopenharmony_ci * this means that during heavy memory pressure, we will sync in this 37562306a36Sopenharmony_ci * function. 37662306a36Sopenharmony_ci * 37762306a36Sopenharmony_ci * Return: Zero on success, -ERESTARTSYS if interrupted and @intr==true 37862306a36Sopenharmony_ci */ 37962306a36Sopenharmony_ciint i915_vma_resource_bind_dep_await(struct i915_address_space *vm, 38062306a36Sopenharmony_ci struct i915_sw_fence *sw_fence, 38162306a36Sopenharmony_ci u64 offset, 38262306a36Sopenharmony_ci u64 size, 38362306a36Sopenharmony_ci bool intr, 38462306a36Sopenharmony_ci gfp_t gfp) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci struct i915_vma_resource *node; 38762306a36Sopenharmony_ci u64 last = offset + size - 1; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci lockdep_assert_held(&vm->mutex); 39062306a36Sopenharmony_ci might_alloc(gfp); 39162306a36Sopenharmony_ci might_sleep(); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci i915_vma_resource_color_adjust_range(vm, &offset, &last); 39462306a36Sopenharmony_ci node = vma_res_itree_iter_first(&vm->pending_unbind, offset, last); 39562306a36Sopenharmony_ci while (node) { 39662306a36Sopenharmony_ci int ret; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci ret = i915_sw_fence_await_dma_fence(sw_fence, 39962306a36Sopenharmony_ci &node->unbind_fence, 40062306a36Sopenharmony_ci 0, gfp); 40162306a36Sopenharmony_ci if (ret < 0) { 40262306a36Sopenharmony_ci ret = dma_fence_wait(&node->unbind_fence, intr); 40362306a36Sopenharmony_ci if (ret) 40462306a36Sopenharmony_ci return ret; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci node = vma_res_itree_iter_next(node, offset, last); 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci return 0; 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_civoid i915_vma_resource_module_exit(void) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci kmem_cache_destroy(slab_vma_resources); 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ciint __init i915_vma_resource_module_init(void) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci slab_vma_resources = KMEM_CACHE(i915_vma_resource, SLAB_HWCACHE_ALIGN); 42162306a36Sopenharmony_ci if (!slab_vma_resources) 42262306a36Sopenharmony_ci return -ENOMEM; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci return 0; 42562306a36Sopenharmony_ci} 426