0001
0002
0003
0004
0005
0006 #include <linux/interval_tree_generic.h>
0007 #include <linux/sched/mm.h>
0008
0009 #include "i915_sw_fence.h"
0010 #include "i915_vma_resource.h"
0011 #include "i915_drv.h"
0012 #include "intel_memory_region.h"
0013
0014 #include "gt/intel_gtt.h"
0015
0016 static struct kmem_cache *slab_vma_resources;
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037 #define VMA_RES_START(_node) ((_node)->start)
0038 #define VMA_RES_LAST(_node) ((_node)->start + (_node)->node_size - 1)
0039 INTERVAL_TREE_DEFINE(struct i915_vma_resource, rb,
0040 u64, __subtree_last,
0041 VMA_RES_START, VMA_RES_LAST, static, vma_res_itree);
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051 struct i915_vma_resource *i915_vma_resource_alloc(void)
0052 {
0053 struct i915_vma_resource *vma_res =
0054 kmem_cache_zalloc(slab_vma_resources, GFP_KERNEL);
0055
0056 return vma_res ? vma_res : ERR_PTR(-ENOMEM);
0057 }
0058
0059
0060
0061
0062
0063 void i915_vma_resource_free(struct i915_vma_resource *vma_res)
0064 {
0065 if (vma_res)
0066 kmem_cache_free(slab_vma_resources, vma_res);
0067 }
0068
0069 static const char *get_driver_name(struct dma_fence *fence)
0070 {
0071 return "vma unbind fence";
0072 }
0073
0074 static const char *get_timeline_name(struct dma_fence *fence)
0075 {
0076 return "unbound";
0077 }
0078
0079 static void unbind_fence_free_rcu(struct rcu_head *head)
0080 {
0081 struct i915_vma_resource *vma_res =
0082 container_of(head, typeof(*vma_res), unbind_fence.rcu);
0083
0084 i915_vma_resource_free(vma_res);
0085 }
0086
0087 static void unbind_fence_release(struct dma_fence *fence)
0088 {
0089 struct i915_vma_resource *vma_res =
0090 container_of(fence, typeof(*vma_res), unbind_fence);
0091
0092 i915_sw_fence_fini(&vma_res->chain);
0093
0094 call_rcu(&fence->rcu, unbind_fence_free_rcu);
0095 }
0096
0097 static struct dma_fence_ops unbind_fence_ops = {
0098 .get_driver_name = get_driver_name,
0099 .get_timeline_name = get_timeline_name,
0100 .release = unbind_fence_release,
0101 };
0102
0103 static void __i915_vma_resource_unhold(struct i915_vma_resource *vma_res)
0104 {
0105 struct i915_address_space *vm;
0106
0107 if (!refcount_dec_and_test(&vma_res->hold_count))
0108 return;
0109
0110 dma_fence_signal(&vma_res->unbind_fence);
0111
0112 vm = vma_res->vm;
0113 if (vma_res->wakeref)
0114 intel_runtime_pm_put(&vm->i915->runtime_pm, vma_res->wakeref);
0115
0116 vma_res->vm = NULL;
0117 if (!RB_EMPTY_NODE(&vma_res->rb)) {
0118 mutex_lock(&vm->mutex);
0119 vma_res_itree_remove(vma_res, &vm->pending_unbind);
0120 mutex_unlock(&vm->mutex);
0121 }
0122
0123 if (vma_res->bi.pages_rsgt)
0124 i915_refct_sgt_put(vma_res->bi.pages_rsgt);
0125 }
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135 void i915_vma_resource_unhold(struct i915_vma_resource *vma_res,
0136 bool lockdep_cookie)
0137 {
0138 dma_fence_end_signalling(lockdep_cookie);
0139
0140 if (IS_ENABLED(CONFIG_PROVE_LOCKING)) {
0141 unsigned long irq_flags;
0142
0143
0144 spin_lock_irqsave(&vma_res->lock, irq_flags);
0145 spin_unlock_irqrestore(&vma_res->lock, irq_flags);
0146 }
0147
0148 __i915_vma_resource_unhold(vma_res);
0149 }
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162 bool i915_vma_resource_hold(struct i915_vma_resource *vma_res,
0163 bool *lockdep_cookie)
0164 {
0165 bool held = refcount_inc_not_zero(&vma_res->hold_count);
0166
0167 if (held)
0168 *lockdep_cookie = dma_fence_begin_signalling();
0169
0170 return held;
0171 }
0172
0173 static void i915_vma_resource_unbind_work(struct work_struct *work)
0174 {
0175 struct i915_vma_resource *vma_res =
0176 container_of(work, typeof(*vma_res), work);
0177 struct i915_address_space *vm = vma_res->vm;
0178 bool lockdep_cookie;
0179
0180 lockdep_cookie = dma_fence_begin_signalling();
0181 if (likely(!vma_res->skip_pte_rewrite))
0182 vma_res->ops->unbind_vma(vm, vma_res);
0183
0184 dma_fence_end_signalling(lockdep_cookie);
0185 __i915_vma_resource_unhold(vma_res);
0186 i915_vma_resource_put(vma_res);
0187 }
0188
0189 static int
0190 i915_vma_resource_fence_notify(struct i915_sw_fence *fence,
0191 enum i915_sw_fence_notify state)
0192 {
0193 struct i915_vma_resource *vma_res =
0194 container_of(fence, typeof(*vma_res), chain);
0195 struct dma_fence *unbind_fence =
0196 &vma_res->unbind_fence;
0197
0198 switch (state) {
0199 case FENCE_COMPLETE:
0200 dma_fence_get(unbind_fence);
0201 if (vma_res->immediate_unbind) {
0202 i915_vma_resource_unbind_work(&vma_res->work);
0203 } else {
0204 INIT_WORK(&vma_res->work, i915_vma_resource_unbind_work);
0205 queue_work(system_unbound_wq, &vma_res->work);
0206 }
0207 break;
0208 case FENCE_FREE:
0209 i915_vma_resource_put(vma_res);
0210 break;
0211 }
0212
0213 return NOTIFY_DONE;
0214 }
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226 struct dma_fence *i915_vma_resource_unbind(struct i915_vma_resource *vma_res,
0227 u32 *tlb)
0228 {
0229 struct i915_address_space *vm = vma_res->vm;
0230
0231 vma_res->tlb = tlb;
0232
0233
0234 i915_vma_resource_get(vma_res);
0235
0236
0237 if (vma_res->needs_wakeref)
0238 vma_res->wakeref = intel_runtime_pm_get_if_in_use(&vm->i915->runtime_pm);
0239
0240 if (atomic_read(&vma_res->chain.pending) <= 1) {
0241 RB_CLEAR_NODE(&vma_res->rb);
0242 vma_res->immediate_unbind = 1;
0243 } else {
0244 vma_res_itree_insert(vma_res, &vma_res->vm->pending_unbind);
0245 }
0246
0247 i915_sw_fence_commit(&vma_res->chain);
0248
0249 return &vma_res->unbind_fence;
0250 }
0251
0252
0253
0254
0255
0256
0257
0258 void __i915_vma_resource_init(struct i915_vma_resource *vma_res)
0259 {
0260 spin_lock_init(&vma_res->lock);
0261 dma_fence_init(&vma_res->unbind_fence, &unbind_fence_ops,
0262 &vma_res->lock, 0, 0);
0263 refcount_set(&vma_res->hold_count, 1);
0264 i915_sw_fence_init(&vma_res->chain, i915_vma_resource_fence_notify);
0265 }
0266
0267 static void
0268 i915_vma_resource_color_adjust_range(struct i915_address_space *vm,
0269 u64 *start,
0270 u64 *end)
0271 {
0272 if (i915_vm_has_cache_coloring(vm)) {
0273 if (*start)
0274 *start -= I915_GTT_PAGE_SIZE;
0275 *end += I915_GTT_PAGE_SIZE;
0276 }
0277 }
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291 int i915_vma_resource_bind_dep_sync(struct i915_address_space *vm,
0292 u64 offset,
0293 u64 size,
0294 bool intr)
0295 {
0296 struct i915_vma_resource *node;
0297 u64 last = offset + size - 1;
0298
0299 lockdep_assert_held(&vm->mutex);
0300 might_sleep();
0301
0302 i915_vma_resource_color_adjust_range(vm, &offset, &last);
0303 node = vma_res_itree_iter_first(&vm->pending_unbind, offset, last);
0304 while (node) {
0305 int ret = dma_fence_wait(&node->unbind_fence, intr);
0306
0307 if (ret)
0308 return ret;
0309
0310 node = vma_res_itree_iter_next(node, offset, last);
0311 }
0312
0313 return 0;
0314 }
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326 void i915_vma_resource_bind_dep_sync_all(struct i915_address_space *vm)
0327 {
0328 struct i915_vma_resource *node;
0329 struct dma_fence *fence;
0330
0331 do {
0332 fence = NULL;
0333 mutex_lock(&vm->mutex);
0334 node = vma_res_itree_iter_first(&vm->pending_unbind, 0,
0335 U64_MAX);
0336 if (node)
0337 fence = dma_fence_get_rcu(&node->unbind_fence);
0338 mutex_unlock(&vm->mutex);
0339
0340 if (fence) {
0341
0342
0343
0344
0345 dma_fence_wait(fence, false);
0346 dma_fence_put(fence);
0347 }
0348 } while (node);
0349 }
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375 int i915_vma_resource_bind_dep_await(struct i915_address_space *vm,
0376 struct i915_sw_fence *sw_fence,
0377 u64 offset,
0378 u64 size,
0379 bool intr,
0380 gfp_t gfp)
0381 {
0382 struct i915_vma_resource *node;
0383 u64 last = offset + size - 1;
0384
0385 lockdep_assert_held(&vm->mutex);
0386 might_alloc(gfp);
0387 might_sleep();
0388
0389 i915_vma_resource_color_adjust_range(vm, &offset, &last);
0390 node = vma_res_itree_iter_first(&vm->pending_unbind, offset, last);
0391 while (node) {
0392 int ret;
0393
0394 ret = i915_sw_fence_await_dma_fence(sw_fence,
0395 &node->unbind_fence,
0396 0, gfp);
0397 if (ret < 0) {
0398 ret = dma_fence_wait(&node->unbind_fence, intr);
0399 if (ret)
0400 return ret;
0401 }
0402
0403 node = vma_res_itree_iter_next(node, offset, last);
0404 }
0405
0406 return 0;
0407 }
0408
0409 void i915_vma_resource_module_exit(void)
0410 {
0411 kmem_cache_destroy(slab_vma_resources);
0412 }
0413
0414 int __init i915_vma_resource_module_init(void)
0415 {
0416 slab_vma_resources = KMEM_CACHE(i915_vma_resource, SLAB_HWCACHE_ALIGN);
0417 if (!slab_vma_resources)
0418 return -ENOMEM;
0419
0420 return 0;
0421 }