0001
0002
0003
0004
0005
0006 #include <linux/sort.h>
0007
0008 #include "gem/i915_gem_internal.h"
0009
0010 #include "selftests/i915_random.h"
0011
0012 static const unsigned int sizes[] = {
0013 SZ_4K,
0014 SZ_64K,
0015 SZ_2M,
0016 CHUNK_SZ - SZ_4K,
0017 CHUNK_SZ,
0018 CHUNK_SZ + SZ_4K,
0019 SZ_64M,
0020 };
0021
0022 static struct drm_i915_gem_object *
0023 create_lmem_or_internal(struct drm_i915_private *i915, size_t size)
0024 {
0025 struct drm_i915_gem_object *obj;
0026
0027 obj = i915_gem_object_create_lmem(i915, size, 0);
0028 if (!IS_ERR(obj))
0029 return obj;
0030
0031 return i915_gem_object_create_internal(i915, size);
0032 }
0033
0034 static int copy(struct intel_migrate *migrate,
0035 int (*fn)(struct intel_migrate *migrate,
0036 struct i915_gem_ww_ctx *ww,
0037 struct drm_i915_gem_object *src,
0038 struct drm_i915_gem_object *dst,
0039 struct i915_request **out),
0040 u32 sz, struct rnd_state *prng)
0041 {
0042 struct drm_i915_private *i915 = migrate->context->engine->i915;
0043 struct drm_i915_gem_object *src, *dst;
0044 struct i915_request *rq;
0045 struct i915_gem_ww_ctx ww;
0046 u32 *vaddr;
0047 int err = 0;
0048 int i;
0049
0050 src = create_lmem_or_internal(i915, sz);
0051 if (IS_ERR(src))
0052 return 0;
0053
0054 sz = src->base.size;
0055 dst = i915_gem_object_create_internal(i915, sz);
0056 if (IS_ERR(dst))
0057 goto err_free_src;
0058
0059 for_i915_gem_ww(&ww, err, true) {
0060 err = i915_gem_object_lock(src, &ww);
0061 if (err)
0062 continue;
0063
0064 err = i915_gem_object_lock(dst, &ww);
0065 if (err)
0066 continue;
0067
0068 vaddr = i915_gem_object_pin_map(src, I915_MAP_WC);
0069 if (IS_ERR(vaddr)) {
0070 err = PTR_ERR(vaddr);
0071 continue;
0072 }
0073
0074 for (i = 0; i < sz / sizeof(u32); i++)
0075 vaddr[i] = i;
0076 i915_gem_object_flush_map(src);
0077
0078 vaddr = i915_gem_object_pin_map(dst, I915_MAP_WC);
0079 if (IS_ERR(vaddr)) {
0080 err = PTR_ERR(vaddr);
0081 goto unpin_src;
0082 }
0083
0084 for (i = 0; i < sz / sizeof(u32); i++)
0085 vaddr[i] = ~i;
0086 i915_gem_object_flush_map(dst);
0087
0088 err = fn(migrate, &ww, src, dst, &rq);
0089 if (!err)
0090 continue;
0091
0092 if (err != -EDEADLK && err != -EINTR && err != -ERESTARTSYS)
0093 pr_err("%ps failed, size: %u\n", fn, sz);
0094 if (rq) {
0095 i915_request_wait(rq, 0, HZ);
0096 i915_request_put(rq);
0097 }
0098 i915_gem_object_unpin_map(dst);
0099 unpin_src:
0100 i915_gem_object_unpin_map(src);
0101 }
0102 if (err)
0103 goto err_out;
0104
0105 if (rq) {
0106 if (i915_request_wait(rq, 0, HZ) < 0) {
0107 pr_err("%ps timed out, size: %u\n", fn, sz);
0108 err = -ETIME;
0109 }
0110 i915_request_put(rq);
0111 }
0112
0113 for (i = 0; !err && i < sz / PAGE_SIZE; i++) {
0114 int x = i * 1024 + i915_prandom_u32_max_state(1024, prng);
0115
0116 if (vaddr[x] != x) {
0117 pr_err("%ps failed, size: %u, offset: %zu\n",
0118 fn, sz, x * sizeof(u32));
0119 igt_hexdump(vaddr + i * 1024, 4096);
0120 err = -EINVAL;
0121 }
0122 }
0123
0124 i915_gem_object_unpin_map(dst);
0125 i915_gem_object_unpin_map(src);
0126
0127 err_out:
0128 i915_gem_object_put(dst);
0129 err_free_src:
0130 i915_gem_object_put(src);
0131
0132 return err;
0133 }
0134
0135 static int intel_context_copy_ccs(struct intel_context *ce,
0136 const struct i915_deps *deps,
0137 struct scatterlist *sg,
0138 enum i915_cache_level cache_level,
0139 bool write_to_ccs,
0140 struct i915_request **out)
0141 {
0142 u8 src_access = write_to_ccs ? DIRECT_ACCESS : INDIRECT_ACCESS;
0143 u8 dst_access = write_to_ccs ? INDIRECT_ACCESS : DIRECT_ACCESS;
0144 struct sgt_dma it = sg_sgt(sg);
0145 struct i915_request *rq;
0146 u32 offset;
0147 int err;
0148
0149 GEM_BUG_ON(ce->vm != ce->engine->gt->migrate.context->vm);
0150 *out = NULL;
0151
0152 GEM_BUG_ON(ce->ring->size < SZ_64K);
0153
0154 offset = 0;
0155 if (HAS_64K_PAGES(ce->engine->i915))
0156 offset = CHUNK_SZ;
0157
0158 do {
0159 int len;
0160
0161 rq = i915_request_create(ce);
0162 if (IS_ERR(rq)) {
0163 err = PTR_ERR(rq);
0164 goto out_ce;
0165 }
0166
0167 if (deps) {
0168 err = i915_request_await_deps(rq, deps);
0169 if (err)
0170 goto out_rq;
0171
0172 if (rq->engine->emit_init_breadcrumb) {
0173 err = rq->engine->emit_init_breadcrumb(rq);
0174 if (err)
0175 goto out_rq;
0176 }
0177
0178 deps = NULL;
0179 }
0180
0181
0182 err = emit_no_arbitration(rq);
0183 if (err)
0184 goto out_rq;
0185
0186 len = emit_pte(rq, &it, cache_level, true, offset, CHUNK_SZ);
0187 if (len <= 0) {
0188 err = len;
0189 goto out_rq;
0190 }
0191
0192 err = rq->engine->emit_flush(rq, EMIT_INVALIDATE);
0193 if (err)
0194 goto out_rq;
0195
0196 err = emit_copy_ccs(rq, offset, dst_access,
0197 offset, src_access, len);
0198 if (err)
0199 goto out_rq;
0200
0201 err = rq->engine->emit_flush(rq, EMIT_INVALIDATE);
0202
0203
0204 out_rq:
0205 if (*out)
0206 i915_request_put(*out);
0207 *out = i915_request_get(rq);
0208 i915_request_add(rq);
0209 if (err || !it.sg || !sg_dma_len(it.sg))
0210 break;
0211
0212 cond_resched();
0213 } while (1);
0214
0215 out_ce:
0216 return err;
0217 }
0218
0219 static int
0220 intel_migrate_ccs_copy(struct intel_migrate *m,
0221 struct i915_gem_ww_ctx *ww,
0222 const struct i915_deps *deps,
0223 struct scatterlist *sg,
0224 enum i915_cache_level cache_level,
0225 bool write_to_ccs,
0226 struct i915_request **out)
0227 {
0228 struct intel_context *ce;
0229 int err;
0230
0231 *out = NULL;
0232 if (!m->context)
0233 return -ENODEV;
0234
0235 ce = intel_migrate_create_context(m);
0236 if (IS_ERR(ce))
0237 ce = intel_context_get(m->context);
0238 GEM_BUG_ON(IS_ERR(ce));
0239
0240 err = intel_context_pin_ww(ce, ww);
0241 if (err)
0242 goto out;
0243
0244 err = intel_context_copy_ccs(ce, deps, sg, cache_level,
0245 write_to_ccs, out);
0246
0247 intel_context_unpin(ce);
0248 out:
0249 intel_context_put(ce);
0250 return err;
0251 }
0252
0253 static int clear(struct intel_migrate *migrate,
0254 int (*fn)(struct intel_migrate *migrate,
0255 struct i915_gem_ww_ctx *ww,
0256 struct drm_i915_gem_object *obj,
0257 u32 value,
0258 struct i915_request **out),
0259 u32 sz, struct rnd_state *prng)
0260 {
0261 struct drm_i915_private *i915 = migrate->context->engine->i915;
0262 struct drm_i915_gem_object *obj;
0263 struct i915_request *rq;
0264 struct i915_gem_ww_ctx ww;
0265 u32 *vaddr, val = 0;
0266 bool ccs_cap = false;
0267 int err = 0;
0268 int i;
0269
0270 obj = create_lmem_or_internal(i915, sz);
0271 if (IS_ERR(obj))
0272 return 0;
0273
0274
0275 sz = obj->base.size;
0276
0277 if (HAS_FLAT_CCS(i915) && i915_gem_object_is_lmem(obj))
0278 ccs_cap = true;
0279
0280 for_i915_gem_ww(&ww, err, true) {
0281 int ccs_bytes, ccs_bytes_per_chunk;
0282
0283 err = i915_gem_object_lock(obj, &ww);
0284 if (err)
0285 continue;
0286
0287 vaddr = i915_gem_object_pin_map(obj, I915_MAP_WC);
0288 if (IS_ERR(vaddr)) {
0289 err = PTR_ERR(vaddr);
0290 continue;
0291 }
0292
0293 for (i = 0; i < sz / sizeof(u32); i++)
0294 vaddr[i] = ~i;
0295 i915_gem_object_flush_map(obj);
0296
0297 if (ccs_cap && !val) {
0298
0299 err = intel_migrate_ccs_copy(migrate, &ww, NULL,
0300 obj->mm.pages->sgl,
0301 obj->cache_level,
0302 true, &rq);
0303 if (rq && !err) {
0304 if (i915_request_wait(rq, 0, HZ) < 0) {
0305 pr_err("%ps timed out, size: %u\n",
0306 fn, sz);
0307 err = -ETIME;
0308 }
0309 i915_request_put(rq);
0310 rq = NULL;
0311 }
0312 if (err)
0313 continue;
0314 }
0315
0316 err = fn(migrate, &ww, obj, val, &rq);
0317 if (rq && !err) {
0318 if (i915_request_wait(rq, 0, HZ) < 0) {
0319 pr_err("%ps timed out, size: %u\n", fn, sz);
0320 err = -ETIME;
0321 }
0322 i915_request_put(rq);
0323 rq = NULL;
0324 }
0325 if (err)
0326 continue;
0327
0328 i915_gem_object_flush_map(obj);
0329
0330
0331 for (i = 0; !err && i < sz / PAGE_SIZE; i++) {
0332 int x = i * 1024 +
0333 i915_prandom_u32_max_state(1024, prng);
0334
0335 if (vaddr[x] != val) {
0336 pr_err("%ps failed, (%u != %u), offset: %zu\n",
0337 fn, vaddr[x], val, x * sizeof(u32));
0338 igt_hexdump(vaddr + i * 1024, 4096);
0339 err = -EINVAL;
0340 }
0341 }
0342 if (err)
0343 continue;
0344
0345 if (ccs_cap && !val) {
0346 for (i = 0; i < sz / sizeof(u32); i++)
0347 vaddr[i] = ~i;
0348 i915_gem_object_flush_map(obj);
0349
0350 err = intel_migrate_ccs_copy(migrate, &ww, NULL,
0351 obj->mm.pages->sgl,
0352 obj->cache_level,
0353 false, &rq);
0354 if (rq && !err) {
0355 if (i915_request_wait(rq, 0, HZ) < 0) {
0356 pr_err("%ps timed out, size: %u\n",
0357 fn, sz);
0358 err = -ETIME;
0359 }
0360 i915_request_put(rq);
0361 rq = NULL;
0362 }
0363 if (err)
0364 continue;
0365
0366 ccs_bytes = GET_CCS_BYTES(i915, sz);
0367 ccs_bytes_per_chunk = GET_CCS_BYTES(i915, CHUNK_SZ);
0368 i915_gem_object_flush_map(obj);
0369
0370 for (i = 0; !err && i < DIV_ROUND_UP(ccs_bytes, PAGE_SIZE); i++) {
0371 int offset = ((i * PAGE_SIZE) /
0372 ccs_bytes_per_chunk) * CHUNK_SZ / sizeof(u32);
0373 int ccs_bytes_left = (ccs_bytes - i * PAGE_SIZE) / sizeof(u32);
0374 int x = i915_prandom_u32_max_state(min_t(int, 1024,
0375 ccs_bytes_left), prng);
0376
0377 if (vaddr[offset + x]) {
0378 pr_err("%ps ccs clearing failed, offset: %ld/%d\n",
0379 fn, i * PAGE_SIZE + x * sizeof(u32), ccs_bytes);
0380 igt_hexdump(vaddr + offset,
0381 min_t(int, 4096,
0382 ccs_bytes_left * sizeof(u32)));
0383 err = -EINVAL;
0384 }
0385 }
0386
0387 if (err)
0388 continue;
0389 }
0390 i915_gem_object_unpin_map(obj);
0391 }
0392
0393 if (err) {
0394 if (err != -EDEADLK && err != -EINTR && err != -ERESTARTSYS)
0395 pr_err("%ps failed, size: %u\n", fn, sz);
0396 if (rq && err != -EINVAL) {
0397 i915_request_wait(rq, 0, HZ);
0398 i915_request_put(rq);
0399 }
0400
0401 i915_gem_object_unpin_map(obj);
0402 }
0403
0404 i915_gem_object_put(obj);
0405 return err;
0406 }
0407
0408 static int __migrate_copy(struct intel_migrate *migrate,
0409 struct i915_gem_ww_ctx *ww,
0410 struct drm_i915_gem_object *src,
0411 struct drm_i915_gem_object *dst,
0412 struct i915_request **out)
0413 {
0414 return intel_migrate_copy(migrate, ww, NULL,
0415 src->mm.pages->sgl, src->cache_level,
0416 i915_gem_object_is_lmem(src),
0417 dst->mm.pages->sgl, dst->cache_level,
0418 i915_gem_object_is_lmem(dst),
0419 out);
0420 }
0421
0422 static int __global_copy(struct intel_migrate *migrate,
0423 struct i915_gem_ww_ctx *ww,
0424 struct drm_i915_gem_object *src,
0425 struct drm_i915_gem_object *dst,
0426 struct i915_request **out)
0427 {
0428 return intel_context_migrate_copy(migrate->context, NULL,
0429 src->mm.pages->sgl, src->cache_level,
0430 i915_gem_object_is_lmem(src),
0431 dst->mm.pages->sgl, dst->cache_level,
0432 i915_gem_object_is_lmem(dst),
0433 out);
0434 }
0435
0436 static int
0437 migrate_copy(struct intel_migrate *migrate, u32 sz, struct rnd_state *prng)
0438 {
0439 return copy(migrate, __migrate_copy, sz, prng);
0440 }
0441
0442 static int
0443 global_copy(struct intel_migrate *migrate, u32 sz, struct rnd_state *prng)
0444 {
0445 return copy(migrate, __global_copy, sz, prng);
0446 }
0447
0448 static int __migrate_clear(struct intel_migrate *migrate,
0449 struct i915_gem_ww_ctx *ww,
0450 struct drm_i915_gem_object *obj,
0451 u32 value,
0452 struct i915_request **out)
0453 {
0454 return intel_migrate_clear(migrate, ww, NULL,
0455 obj->mm.pages->sgl,
0456 obj->cache_level,
0457 i915_gem_object_is_lmem(obj),
0458 value, out);
0459 }
0460
0461 static int __global_clear(struct intel_migrate *migrate,
0462 struct i915_gem_ww_ctx *ww,
0463 struct drm_i915_gem_object *obj,
0464 u32 value,
0465 struct i915_request **out)
0466 {
0467 return intel_context_migrate_clear(migrate->context, NULL,
0468 obj->mm.pages->sgl,
0469 obj->cache_level,
0470 i915_gem_object_is_lmem(obj),
0471 value, out);
0472 }
0473
0474 static int
0475 migrate_clear(struct intel_migrate *migrate, u32 sz, struct rnd_state *prng)
0476 {
0477 return clear(migrate, __migrate_clear, sz, prng);
0478 }
0479
0480 static int
0481 global_clear(struct intel_migrate *migrate, u32 sz, struct rnd_state *prng)
0482 {
0483 return clear(migrate, __global_clear, sz, prng);
0484 }
0485
0486 static int live_migrate_copy(void *arg)
0487 {
0488 struct intel_migrate *migrate = arg;
0489 struct drm_i915_private *i915 = migrate->context->engine->i915;
0490 I915_RND_STATE(prng);
0491 int i;
0492
0493 for (i = 0; i < ARRAY_SIZE(sizes); i++) {
0494 int err;
0495
0496 err = migrate_copy(migrate, sizes[i], &prng);
0497 if (err == 0)
0498 err = global_copy(migrate, sizes[i], &prng);
0499 i915_gem_drain_freed_objects(i915);
0500 if (err)
0501 return err;
0502 }
0503
0504 return 0;
0505 }
0506
0507 static int live_migrate_clear(void *arg)
0508 {
0509 struct intel_migrate *migrate = arg;
0510 struct drm_i915_private *i915 = migrate->context->engine->i915;
0511 I915_RND_STATE(prng);
0512 int i;
0513
0514 for (i = 0; i < ARRAY_SIZE(sizes); i++) {
0515 int err;
0516
0517 err = migrate_clear(migrate, sizes[i], &prng);
0518 if (err == 0)
0519 err = global_clear(migrate, sizes[i], &prng);
0520
0521 i915_gem_drain_freed_objects(i915);
0522 if (err)
0523 return err;
0524 }
0525
0526 return 0;
0527 }
0528
0529 struct threaded_migrate {
0530 struct intel_migrate *migrate;
0531 struct task_struct *tsk;
0532 struct rnd_state prng;
0533 };
0534
0535 static int threaded_migrate(struct intel_migrate *migrate,
0536 int (*fn)(void *arg),
0537 unsigned int flags)
0538 {
0539 const unsigned int n_cpus = num_online_cpus() + 1;
0540 struct threaded_migrate *thread;
0541 I915_RND_STATE(prng);
0542 unsigned int i;
0543 int err = 0;
0544
0545 thread = kcalloc(n_cpus, sizeof(*thread), GFP_KERNEL);
0546 if (!thread)
0547 return 0;
0548
0549 for (i = 0; i < n_cpus; ++i) {
0550 struct task_struct *tsk;
0551
0552 thread[i].migrate = migrate;
0553 thread[i].prng =
0554 I915_RND_STATE_INITIALIZER(prandom_u32_state(&prng));
0555
0556 tsk = kthread_run(fn, &thread[i], "igt-%d", i);
0557 if (IS_ERR(tsk)) {
0558 err = PTR_ERR(tsk);
0559 break;
0560 }
0561
0562 get_task_struct(tsk);
0563 thread[i].tsk = tsk;
0564 }
0565
0566 msleep(10);
0567
0568 for (i = 0; i < n_cpus; ++i) {
0569 struct task_struct *tsk = thread[i].tsk;
0570 int status;
0571
0572 if (IS_ERR_OR_NULL(tsk))
0573 continue;
0574
0575 status = kthread_stop(tsk);
0576 if (status && !err)
0577 err = status;
0578
0579 put_task_struct(tsk);
0580 }
0581
0582 kfree(thread);
0583 return err;
0584 }
0585
0586 static int __thread_migrate_copy(void *arg)
0587 {
0588 struct threaded_migrate *tm = arg;
0589
0590 return migrate_copy(tm->migrate, 2 * CHUNK_SZ, &tm->prng);
0591 }
0592
0593 static int thread_migrate_copy(void *arg)
0594 {
0595 return threaded_migrate(arg, __thread_migrate_copy, 0);
0596 }
0597
0598 static int __thread_global_copy(void *arg)
0599 {
0600 struct threaded_migrate *tm = arg;
0601
0602 return global_copy(tm->migrate, 2 * CHUNK_SZ, &tm->prng);
0603 }
0604
0605 static int thread_global_copy(void *arg)
0606 {
0607 return threaded_migrate(arg, __thread_global_copy, 0);
0608 }
0609
0610 static int __thread_migrate_clear(void *arg)
0611 {
0612 struct threaded_migrate *tm = arg;
0613
0614 return migrate_clear(tm->migrate, 2 * CHUNK_SZ, &tm->prng);
0615 }
0616
0617 static int __thread_global_clear(void *arg)
0618 {
0619 struct threaded_migrate *tm = arg;
0620
0621 return global_clear(tm->migrate, 2 * CHUNK_SZ, &tm->prng);
0622 }
0623
0624 static int thread_migrate_clear(void *arg)
0625 {
0626 return threaded_migrate(arg, __thread_migrate_clear, 0);
0627 }
0628
0629 static int thread_global_clear(void *arg)
0630 {
0631 return threaded_migrate(arg, __thread_global_clear, 0);
0632 }
0633
0634 int intel_migrate_live_selftests(struct drm_i915_private *i915)
0635 {
0636 static const struct i915_subtest tests[] = {
0637 SUBTEST(live_migrate_copy),
0638 SUBTEST(live_migrate_clear),
0639 SUBTEST(thread_migrate_copy),
0640 SUBTEST(thread_migrate_clear),
0641 SUBTEST(thread_global_copy),
0642 SUBTEST(thread_global_clear),
0643 };
0644 struct intel_gt *gt = to_gt(i915);
0645
0646 if (!gt->migrate.context)
0647 return 0;
0648
0649 return i915_subtests(tests, >->migrate);
0650 }
0651
0652 static struct drm_i915_gem_object *
0653 create_init_lmem_internal(struct intel_gt *gt, size_t sz, bool try_lmem)
0654 {
0655 struct drm_i915_gem_object *obj = NULL;
0656 int err;
0657
0658 if (try_lmem)
0659 obj = i915_gem_object_create_lmem(gt->i915, sz, 0);
0660
0661 if (IS_ERR_OR_NULL(obj)) {
0662 obj = i915_gem_object_create_internal(gt->i915, sz);
0663 if (IS_ERR(obj))
0664 return obj;
0665 }
0666
0667 i915_gem_object_trylock(obj, NULL);
0668 err = i915_gem_object_pin_pages(obj);
0669 if (err) {
0670 i915_gem_object_unlock(obj);
0671 i915_gem_object_put(obj);
0672 return ERR_PTR(err);
0673 }
0674
0675 return obj;
0676 }
0677
0678 static int wrap_ktime_compare(const void *A, const void *B)
0679 {
0680 const ktime_t *a = A, *b = B;
0681
0682 return ktime_compare(*a, *b);
0683 }
0684
0685 static int __perf_clear_blt(struct intel_context *ce,
0686 struct scatterlist *sg,
0687 enum i915_cache_level cache_level,
0688 bool is_lmem,
0689 size_t sz)
0690 {
0691 ktime_t t[5];
0692 int pass;
0693 int err = 0;
0694
0695 for (pass = 0; pass < ARRAY_SIZE(t); pass++) {
0696 struct i915_request *rq;
0697 ktime_t t0, t1;
0698
0699 t0 = ktime_get();
0700
0701 err = intel_context_migrate_clear(ce, NULL, sg, cache_level,
0702 is_lmem, 0, &rq);
0703 if (rq) {
0704 if (i915_request_wait(rq, 0, MAX_SCHEDULE_TIMEOUT) < 0)
0705 err = -EIO;
0706 i915_request_put(rq);
0707 }
0708 if (err)
0709 break;
0710
0711 t1 = ktime_get();
0712 t[pass] = ktime_sub(t1, t0);
0713 }
0714 if (err)
0715 return err;
0716
0717 sort(t, ARRAY_SIZE(t), sizeof(*t), wrap_ktime_compare, NULL);
0718 pr_info("%s: %zd KiB fill: %lld MiB/s\n",
0719 ce->engine->name, sz >> 10,
0720 div64_u64(mul_u32_u32(4 * sz,
0721 1000 * 1000 * 1000),
0722 t[1] + 2 * t[2] + t[3]) >> 20);
0723 return 0;
0724 }
0725
0726 static int perf_clear_blt(void *arg)
0727 {
0728 struct intel_gt *gt = arg;
0729 static const unsigned long sizes[] = {
0730 SZ_4K,
0731 SZ_64K,
0732 SZ_2M,
0733 SZ_64M
0734 };
0735 int i;
0736
0737 for (i = 0; i < ARRAY_SIZE(sizes); i++) {
0738 struct drm_i915_gem_object *dst;
0739 int err;
0740
0741 dst = create_init_lmem_internal(gt, sizes[i], true);
0742 if (IS_ERR(dst))
0743 return PTR_ERR(dst);
0744
0745 err = __perf_clear_blt(gt->migrate.context,
0746 dst->mm.pages->sgl,
0747 I915_CACHE_NONE,
0748 i915_gem_object_is_lmem(dst),
0749 sizes[i]);
0750
0751 i915_gem_object_unlock(dst);
0752 i915_gem_object_put(dst);
0753 if (err)
0754 return err;
0755 }
0756
0757 return 0;
0758 }
0759
0760 static int __perf_copy_blt(struct intel_context *ce,
0761 struct scatterlist *src,
0762 enum i915_cache_level src_cache_level,
0763 bool src_is_lmem,
0764 struct scatterlist *dst,
0765 enum i915_cache_level dst_cache_level,
0766 bool dst_is_lmem,
0767 size_t sz)
0768 {
0769 ktime_t t[5];
0770 int pass;
0771 int err = 0;
0772
0773 for (pass = 0; pass < ARRAY_SIZE(t); pass++) {
0774 struct i915_request *rq;
0775 ktime_t t0, t1;
0776
0777 t0 = ktime_get();
0778
0779 err = intel_context_migrate_copy(ce, NULL,
0780 src, src_cache_level,
0781 src_is_lmem,
0782 dst, dst_cache_level,
0783 dst_is_lmem,
0784 &rq);
0785 if (rq) {
0786 if (i915_request_wait(rq, 0, MAX_SCHEDULE_TIMEOUT) < 0)
0787 err = -EIO;
0788 i915_request_put(rq);
0789 }
0790 if (err)
0791 break;
0792
0793 t1 = ktime_get();
0794 t[pass] = ktime_sub(t1, t0);
0795 }
0796 if (err)
0797 return err;
0798
0799 sort(t, ARRAY_SIZE(t), sizeof(*t), wrap_ktime_compare, NULL);
0800 pr_info("%s: %zd KiB copy: %lld MiB/s\n",
0801 ce->engine->name, sz >> 10,
0802 div64_u64(mul_u32_u32(4 * sz,
0803 1000 * 1000 * 1000),
0804 t[1] + 2 * t[2] + t[3]) >> 20);
0805 return 0;
0806 }
0807
0808 static int perf_copy_blt(void *arg)
0809 {
0810 struct intel_gt *gt = arg;
0811 static const unsigned long sizes[] = {
0812 SZ_4K,
0813 SZ_64K,
0814 SZ_2M,
0815 SZ_64M
0816 };
0817 int i;
0818
0819 for (i = 0; i < ARRAY_SIZE(sizes); i++) {
0820 struct drm_i915_gem_object *src, *dst;
0821 size_t sz;
0822 int err;
0823
0824 src = create_init_lmem_internal(gt, sizes[i], true);
0825 if (IS_ERR(src))
0826 return PTR_ERR(src);
0827
0828 sz = src->base.size;
0829 dst = create_init_lmem_internal(gt, sz, false);
0830 if (IS_ERR(dst)) {
0831 err = PTR_ERR(dst);
0832 goto err_src;
0833 }
0834
0835 err = __perf_copy_blt(gt->migrate.context,
0836 src->mm.pages->sgl,
0837 I915_CACHE_NONE,
0838 i915_gem_object_is_lmem(src),
0839 dst->mm.pages->sgl,
0840 I915_CACHE_NONE,
0841 i915_gem_object_is_lmem(dst),
0842 sz);
0843
0844 i915_gem_object_unlock(dst);
0845 i915_gem_object_put(dst);
0846 err_src:
0847 i915_gem_object_unlock(src);
0848 i915_gem_object_put(src);
0849 if (err)
0850 return err;
0851 }
0852
0853 return 0;
0854 }
0855
0856 int intel_migrate_perf_selftests(struct drm_i915_private *i915)
0857 {
0858 static const struct i915_subtest tests[] = {
0859 SUBTEST(perf_clear_blt),
0860 SUBTEST(perf_copy_blt),
0861 };
0862 struct intel_gt *gt = to_gt(i915);
0863
0864 if (intel_gt_is_wedged(gt))
0865 return 0;
0866
0867 if (!gt->migrate.context)
0868 return 0;
0869
0870 return intel_gt_live_subtests(tests, gt);
0871 }