0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029 #include "gem/i915_gem_context.h"
0030 #include "gt/intel_gt.h"
0031 #include "gt/intel_gt_requests.h"
0032
0033 #include "i915_drv.h"
0034 #include "i915_gem_evict.h"
0035 #include "i915_trace.h"
0036
0037 I915_SELFTEST_DECLARE(static struct igt_evict_ctl {
0038 bool fail_if_busy:1;
0039 } igt_evict_ctl;)
0040
0041 static bool dying_vma(struct i915_vma *vma)
0042 {
0043 return !kref_read(&vma->obj->base.refcount);
0044 }
0045
0046 static int ggtt_flush(struct intel_gt *gt)
0047 {
0048
0049
0050
0051
0052
0053
0054
0055 return intel_gt_wait_for_idle(gt, MAX_SCHEDULE_TIMEOUT);
0056 }
0057
0058 static bool grab_vma(struct i915_vma *vma, struct i915_gem_ww_ctx *ww)
0059 {
0060
0061
0062
0063
0064 if (i915_gem_object_get_rcu(vma->obj)) {
0065 if (!i915_gem_object_trylock(vma->obj, ww)) {
0066 i915_gem_object_put(vma->obj);
0067 return false;
0068 }
0069 } else {
0070
0071 atomic_and(~I915_VMA_PIN_MASK, &vma->flags);
0072 }
0073
0074 return true;
0075 }
0076
0077 static void ungrab_vma(struct i915_vma *vma)
0078 {
0079 if (dying_vma(vma))
0080 return;
0081
0082 i915_gem_object_unlock(vma->obj);
0083 i915_gem_object_put(vma->obj);
0084 }
0085
0086 static bool
0087 mark_free(struct drm_mm_scan *scan,
0088 struct i915_gem_ww_ctx *ww,
0089 struct i915_vma *vma,
0090 unsigned int flags,
0091 struct list_head *unwind)
0092 {
0093 if (i915_vma_is_pinned(vma))
0094 return false;
0095
0096 if (!grab_vma(vma, ww))
0097 return false;
0098
0099 list_add(&vma->evict_link, unwind);
0100 return drm_mm_scan_add_block(scan, &vma->node);
0101 }
0102
0103 static bool defer_evict(struct i915_vma *vma)
0104 {
0105 if (i915_vma_is_active(vma))
0106 return true;
0107
0108 if (i915_vma_is_scanout(vma))
0109 return true;
0110
0111 return false;
0112 }
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138 int
0139 i915_gem_evict_something(struct i915_address_space *vm,
0140 struct i915_gem_ww_ctx *ww,
0141 u64 min_size, u64 alignment,
0142 unsigned long color,
0143 u64 start, u64 end,
0144 unsigned flags)
0145 {
0146 struct drm_mm_scan scan;
0147 struct list_head eviction_list;
0148 struct i915_vma *vma, *next;
0149 struct drm_mm_node *node;
0150 enum drm_mm_insert_mode mode;
0151 struct i915_vma *active;
0152 int ret;
0153
0154 lockdep_assert_held(&vm->mutex);
0155 trace_i915_gem_evict(vm, min_size, alignment, flags);
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168 mode = DRM_MM_INSERT_BEST;
0169 if (flags & PIN_HIGH)
0170 mode = DRM_MM_INSERT_HIGH;
0171 if (flags & PIN_MAPPABLE)
0172 mode = DRM_MM_INSERT_LOW;
0173 drm_mm_scan_init_with_range(&scan, &vm->mm,
0174 min_size, alignment, color,
0175 start, end, mode);
0176
0177 intel_gt_retire_requests(vm->gt);
0178
0179 search_again:
0180 active = NULL;
0181 INIT_LIST_HEAD(&eviction_list);
0182 list_for_each_entry_safe(vma, next, &vm->bound_list, vm_link) {
0183 if (vma == active) {
0184 if (flags & PIN_NONBLOCK)
0185 break;
0186
0187 active = ERR_PTR(-EAGAIN);
0188 }
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205 if (active != ERR_PTR(-EAGAIN) && defer_evict(vma)) {
0206 if (!active)
0207 active = vma;
0208
0209 list_move_tail(&vma->vm_link, &vm->bound_list);
0210 continue;
0211 }
0212
0213 if (mark_free(&scan, ww, vma, flags, &eviction_list))
0214 goto found;
0215 }
0216
0217
0218 list_for_each_entry_safe(vma, next, &eviction_list, evict_link) {
0219 ret = drm_mm_scan_remove_block(&scan, &vma->node);
0220 BUG_ON(ret);
0221 ungrab_vma(vma);
0222 }
0223
0224
0225
0226
0227
0228
0229
0230 if (!i915_is_ggtt(vm) || flags & PIN_NONBLOCK)
0231 return -ENOSPC;
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246 if (I915_SELFTEST_ONLY(igt_evict_ctl.fail_if_busy))
0247 return -EBUSY;
0248
0249 ret = ggtt_flush(vm->gt);
0250 if (ret)
0251 return ret;
0252
0253 cond_resched();
0254
0255 flags |= PIN_NONBLOCK;
0256 goto search_again;
0257
0258 found:
0259
0260
0261
0262
0263
0264
0265 list_for_each_entry_safe(vma, next, &eviction_list, evict_link) {
0266 if (drm_mm_scan_remove_block(&scan, &vma->node)) {
0267 __i915_vma_pin(vma);
0268 } else {
0269 list_del(&vma->evict_link);
0270 ungrab_vma(vma);
0271 }
0272 }
0273
0274
0275 ret = 0;
0276 list_for_each_entry_safe(vma, next, &eviction_list, evict_link) {
0277 __i915_vma_unpin(vma);
0278 if (ret == 0)
0279 ret = __i915_vma_unbind(vma);
0280 ungrab_vma(vma);
0281 }
0282
0283 while (ret == 0 && (node = drm_mm_scan_color_evict(&scan))) {
0284 vma = container_of(node, struct i915_vma, node);
0285
0286
0287 if (vma->node.color != I915_COLOR_UNEVICTABLE &&
0288 grab_vma(vma, ww)) {
0289 ret = __i915_vma_unbind(vma);
0290 ungrab_vma(vma);
0291 } else {
0292 ret = -ENOSPC;
0293 }
0294 }
0295
0296 return ret;
0297 }
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311 int i915_gem_evict_for_node(struct i915_address_space *vm,
0312 struct i915_gem_ww_ctx *ww,
0313 struct drm_mm_node *target,
0314 unsigned int flags)
0315 {
0316 LIST_HEAD(eviction_list);
0317 struct drm_mm_node *node;
0318 u64 start = target->start;
0319 u64 end = start + target->size;
0320 struct i915_vma *vma, *next;
0321 int ret = 0;
0322
0323 lockdep_assert_held(&vm->mutex);
0324 GEM_BUG_ON(!IS_ALIGNED(start, I915_GTT_PAGE_SIZE));
0325 GEM_BUG_ON(!IS_ALIGNED(end, I915_GTT_PAGE_SIZE));
0326
0327 trace_i915_gem_evict_node(vm, target, flags);
0328
0329
0330
0331
0332
0333
0334
0335 intel_gt_retire_requests(vm->gt);
0336
0337 if (i915_vm_has_cache_coloring(vm)) {
0338
0339 if (start)
0340 start -= I915_GTT_PAGE_SIZE;
0341
0342
0343 end += I915_GTT_PAGE_SIZE;
0344 }
0345 GEM_BUG_ON(start >= end);
0346
0347 drm_mm_for_each_node_in_range(node, &vm->mm, start, end) {
0348
0349 if (node->color == I915_COLOR_UNEVICTABLE) {
0350 ret = -ENOSPC;
0351 break;
0352 }
0353
0354 GEM_BUG_ON(!drm_mm_node_allocated(node));
0355 vma = container_of(node, typeof(*vma), node);
0356
0357
0358
0359
0360
0361
0362
0363
0364 if (i915_vm_has_cache_coloring(vm)) {
0365 if (node->start + node->size == target->start) {
0366 if (node->color == target->color)
0367 continue;
0368 }
0369 if (node->start == target->start + target->size) {
0370 if (node->color == target->color)
0371 continue;
0372 }
0373 }
0374
0375 if (i915_vma_is_pinned(vma)) {
0376 ret = -ENOSPC;
0377 break;
0378 }
0379
0380 if (flags & PIN_NONBLOCK && i915_vma_is_active(vma)) {
0381 ret = -ENOSPC;
0382 break;
0383 }
0384
0385 if (!grab_vma(vma, ww)) {
0386 ret = -ENOSPC;
0387 break;
0388 }
0389
0390
0391
0392
0393
0394
0395
0396
0397
0398
0399 __i915_vma_pin(vma);
0400 list_add(&vma->evict_link, &eviction_list);
0401 }
0402
0403 list_for_each_entry_safe(vma, next, &eviction_list, evict_link) {
0404 __i915_vma_unpin(vma);
0405 if (ret == 0)
0406 ret = __i915_vma_unbind(vma);
0407
0408 ungrab_vma(vma);
0409 }
0410
0411 return ret;
0412 }
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428 int i915_gem_evict_vm(struct i915_address_space *vm, struct i915_gem_ww_ctx *ww)
0429 {
0430 int ret = 0;
0431
0432 lockdep_assert_held(&vm->mutex);
0433 trace_i915_gem_evict_vm(vm);
0434
0435
0436
0437
0438
0439
0440 if (i915_is_ggtt(vm)) {
0441 ret = ggtt_flush(vm->gt);
0442 if (ret)
0443 return ret;
0444 }
0445
0446 do {
0447 struct i915_vma *vma, *vn;
0448 LIST_HEAD(eviction_list);
0449 LIST_HEAD(locked_eviction_list);
0450
0451 list_for_each_entry(vma, &vm->bound_list, vm_link) {
0452 if (i915_vma_is_pinned(vma))
0453 continue;
0454
0455
0456
0457
0458
0459
0460 if (dying_vma(vma) ||
0461 (ww && (dma_resv_locking_ctx(vma->obj->base.resv) == &ww->ctx))) {
0462 __i915_vma_pin(vma);
0463 list_add(&vma->evict_link, &locked_eviction_list);
0464 continue;
0465 }
0466
0467 if (!i915_gem_object_trylock(vma->obj, ww))
0468 continue;
0469
0470 __i915_vma_pin(vma);
0471 list_add(&vma->evict_link, &eviction_list);
0472 }
0473 if (list_empty(&eviction_list) && list_empty(&locked_eviction_list))
0474 break;
0475
0476 ret = 0;
0477
0478 list_for_each_entry_safe(vma, vn, &locked_eviction_list, evict_link) {
0479 __i915_vma_unpin(vma);
0480
0481 if (ret == 0)
0482 ret = __i915_vma_unbind(vma);
0483 if (ret != -EINTR)
0484 ret = 0;
0485 }
0486
0487 list_for_each_entry_safe(vma, vn, &eviction_list, evict_link) {
0488 __i915_vma_unpin(vma);
0489 if (ret == 0)
0490 ret = __i915_vma_unbind(vma);
0491 if (ret != -EINTR)
0492 ret = 0;
0493
0494 i915_gem_object_unlock(vma->obj);
0495 }
0496 } while (ret == 0);
0497
0498 return ret;
0499 }
0500
0501 #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
0502 #include "selftests/i915_gem_evict.c"
0503 #endif