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