15ca02815Sjsg // SPDX-License-Identifier: MIT
25ca02815Sjsg /*
35ca02815Sjsg * Copyright © 2020 Intel Corporation
45ca02815Sjsg */
55ca02815Sjsg
65ca02815Sjsg #include <linux/sort.h>
75ca02815Sjsg
81bb76ff1Sjsg #include "gem/i915_gem_internal.h"
9f005ef32Sjsg #include "gem/i915_gem_lmem.h"
101bb76ff1Sjsg
11f005ef32Sjsg #include "selftests/igt_spinner.h"
125ca02815Sjsg #include "selftests/i915_random.h"
135ca02815Sjsg
145ca02815Sjsg static const unsigned int sizes[] = {
155ca02815Sjsg SZ_4K,
165ca02815Sjsg SZ_64K,
175ca02815Sjsg SZ_2M,
185ca02815Sjsg CHUNK_SZ - SZ_4K,
195ca02815Sjsg CHUNK_SZ,
205ca02815Sjsg CHUNK_SZ + SZ_4K,
215ca02815Sjsg SZ_64M,
225ca02815Sjsg };
235ca02815Sjsg
245ca02815Sjsg static struct drm_i915_gem_object *
create_lmem_or_internal(struct drm_i915_private * i915,size_t size)255ca02815Sjsg create_lmem_or_internal(struct drm_i915_private *i915, size_t size)
265ca02815Sjsg {
275ca02815Sjsg struct drm_i915_gem_object *obj;
285ca02815Sjsg
295ca02815Sjsg obj = i915_gem_object_create_lmem(i915, size, 0);
305ca02815Sjsg if (!IS_ERR(obj))
315ca02815Sjsg return obj;
325ca02815Sjsg
335ca02815Sjsg return i915_gem_object_create_internal(i915, size);
345ca02815Sjsg }
355ca02815Sjsg
copy(struct intel_migrate * migrate,int (* fn)(struct intel_migrate * migrate,struct i915_gem_ww_ctx * ww,struct drm_i915_gem_object * src,struct drm_i915_gem_object * dst,struct i915_request ** out),u32 sz,struct rnd_state * prng)365ca02815Sjsg static int copy(struct intel_migrate *migrate,
375ca02815Sjsg int (*fn)(struct intel_migrate *migrate,
385ca02815Sjsg struct i915_gem_ww_ctx *ww,
395ca02815Sjsg struct drm_i915_gem_object *src,
405ca02815Sjsg struct drm_i915_gem_object *dst,
415ca02815Sjsg struct i915_request **out),
425ca02815Sjsg u32 sz, struct rnd_state *prng)
435ca02815Sjsg {
445ca02815Sjsg struct drm_i915_private *i915 = migrate->context->engine->i915;
455ca02815Sjsg struct drm_i915_gem_object *src, *dst;
465ca02815Sjsg struct i915_request *rq;
475ca02815Sjsg struct i915_gem_ww_ctx ww;
485ca02815Sjsg u32 *vaddr;
495ca02815Sjsg int err = 0;
505ca02815Sjsg int i;
515ca02815Sjsg
525ca02815Sjsg src = create_lmem_or_internal(i915, sz);
535ca02815Sjsg if (IS_ERR(src))
545ca02815Sjsg return 0;
555ca02815Sjsg
561bb76ff1Sjsg sz = src->base.size;
575ca02815Sjsg dst = i915_gem_object_create_internal(i915, sz);
585ca02815Sjsg if (IS_ERR(dst))
595ca02815Sjsg goto err_free_src;
605ca02815Sjsg
615ca02815Sjsg for_i915_gem_ww(&ww, err, true) {
625ca02815Sjsg err = i915_gem_object_lock(src, &ww);
635ca02815Sjsg if (err)
645ca02815Sjsg continue;
655ca02815Sjsg
665ca02815Sjsg err = i915_gem_object_lock(dst, &ww);
675ca02815Sjsg if (err)
685ca02815Sjsg continue;
695ca02815Sjsg
705ca02815Sjsg vaddr = i915_gem_object_pin_map(src, I915_MAP_WC);
715ca02815Sjsg if (IS_ERR(vaddr)) {
725ca02815Sjsg err = PTR_ERR(vaddr);
735ca02815Sjsg continue;
745ca02815Sjsg }
755ca02815Sjsg
765ca02815Sjsg for (i = 0; i < sz / sizeof(u32); i++)
775ca02815Sjsg vaddr[i] = i;
785ca02815Sjsg i915_gem_object_flush_map(src);
795ca02815Sjsg
805ca02815Sjsg vaddr = i915_gem_object_pin_map(dst, I915_MAP_WC);
815ca02815Sjsg if (IS_ERR(vaddr)) {
825ca02815Sjsg err = PTR_ERR(vaddr);
835ca02815Sjsg goto unpin_src;
845ca02815Sjsg }
855ca02815Sjsg
865ca02815Sjsg for (i = 0; i < sz / sizeof(u32); i++)
875ca02815Sjsg vaddr[i] = ~i;
885ca02815Sjsg i915_gem_object_flush_map(dst);
895ca02815Sjsg
905ca02815Sjsg err = fn(migrate, &ww, src, dst, &rq);
915ca02815Sjsg if (!err)
925ca02815Sjsg continue;
935ca02815Sjsg
945ca02815Sjsg if (err != -EDEADLK && err != -EINTR && err != -ERESTARTSYS)
955ca02815Sjsg pr_err("%ps failed, size: %u\n", fn, sz);
965ca02815Sjsg if (rq) {
975ca02815Sjsg i915_request_wait(rq, 0, HZ);
985ca02815Sjsg i915_request_put(rq);
995ca02815Sjsg }
1005ca02815Sjsg i915_gem_object_unpin_map(dst);
1015ca02815Sjsg unpin_src:
1025ca02815Sjsg i915_gem_object_unpin_map(src);
1035ca02815Sjsg }
1045ca02815Sjsg if (err)
1055ca02815Sjsg goto err_out;
1065ca02815Sjsg
1075ca02815Sjsg if (rq) {
1085ca02815Sjsg if (i915_request_wait(rq, 0, HZ) < 0) {
1095ca02815Sjsg pr_err("%ps timed out, size: %u\n", fn, sz);
1105ca02815Sjsg err = -ETIME;
1115ca02815Sjsg }
1125ca02815Sjsg i915_request_put(rq);
1135ca02815Sjsg }
1145ca02815Sjsg
1155ca02815Sjsg for (i = 0; !err && i < sz / PAGE_SIZE; i++) {
1165ca02815Sjsg int x = i * 1024 + i915_prandom_u32_max_state(1024, prng);
1175ca02815Sjsg
1185ca02815Sjsg if (vaddr[x] != x) {
1195ca02815Sjsg pr_err("%ps failed, size: %u, offset: %zu\n",
1205ca02815Sjsg fn, sz, x * sizeof(u32));
1215ca02815Sjsg igt_hexdump(vaddr + i * 1024, 4096);
1225ca02815Sjsg err = -EINVAL;
1235ca02815Sjsg }
1245ca02815Sjsg }
1255ca02815Sjsg
1265ca02815Sjsg i915_gem_object_unpin_map(dst);
1275ca02815Sjsg i915_gem_object_unpin_map(src);
1285ca02815Sjsg
1295ca02815Sjsg err_out:
1305ca02815Sjsg i915_gem_object_put(dst);
1315ca02815Sjsg err_free_src:
1325ca02815Sjsg i915_gem_object_put(src);
1335ca02815Sjsg
1345ca02815Sjsg return err;
1355ca02815Sjsg }
1365ca02815Sjsg
intel_context_copy_ccs(struct intel_context * ce,const struct i915_deps * deps,struct scatterlist * sg,unsigned int pat_index,bool write_to_ccs,struct i915_request ** out)1371bb76ff1Sjsg static int intel_context_copy_ccs(struct intel_context *ce,
1381bb76ff1Sjsg const struct i915_deps *deps,
1391bb76ff1Sjsg struct scatterlist *sg,
140f005ef32Sjsg unsigned int pat_index,
1411bb76ff1Sjsg bool write_to_ccs,
1421bb76ff1Sjsg struct i915_request **out)
1431bb76ff1Sjsg {
1441bb76ff1Sjsg u8 src_access = write_to_ccs ? DIRECT_ACCESS : INDIRECT_ACCESS;
1451bb76ff1Sjsg u8 dst_access = write_to_ccs ? INDIRECT_ACCESS : DIRECT_ACCESS;
1461bb76ff1Sjsg struct sgt_dma it = sg_sgt(sg);
1471bb76ff1Sjsg struct i915_request *rq;
1481bb76ff1Sjsg u32 offset;
1491bb76ff1Sjsg int err;
1501bb76ff1Sjsg
1511bb76ff1Sjsg GEM_BUG_ON(ce->vm != ce->engine->gt->migrate.context->vm);
1521bb76ff1Sjsg *out = NULL;
1531bb76ff1Sjsg
1541bb76ff1Sjsg GEM_BUG_ON(ce->ring->size < SZ_64K);
1551bb76ff1Sjsg
1561bb76ff1Sjsg offset = 0;
1571bb76ff1Sjsg if (HAS_64K_PAGES(ce->engine->i915))
1581bb76ff1Sjsg offset = CHUNK_SZ;
1591bb76ff1Sjsg
1601bb76ff1Sjsg do {
1611bb76ff1Sjsg int len;
1621bb76ff1Sjsg
1631bb76ff1Sjsg rq = i915_request_create(ce);
1641bb76ff1Sjsg if (IS_ERR(rq)) {
1651bb76ff1Sjsg err = PTR_ERR(rq);
1661bb76ff1Sjsg goto out_ce;
1671bb76ff1Sjsg }
1681bb76ff1Sjsg
1691bb76ff1Sjsg if (deps) {
1701bb76ff1Sjsg err = i915_request_await_deps(rq, deps);
1711bb76ff1Sjsg if (err)
1721bb76ff1Sjsg goto out_rq;
1731bb76ff1Sjsg
1741bb76ff1Sjsg if (rq->engine->emit_init_breadcrumb) {
1751bb76ff1Sjsg err = rq->engine->emit_init_breadcrumb(rq);
1761bb76ff1Sjsg if (err)
1771bb76ff1Sjsg goto out_rq;
1781bb76ff1Sjsg }
1791bb76ff1Sjsg
1801bb76ff1Sjsg deps = NULL;
1811bb76ff1Sjsg }
1821bb76ff1Sjsg
1831bb76ff1Sjsg /* The PTE updates + clear must not be interrupted. */
1841bb76ff1Sjsg err = emit_no_arbitration(rq);
1851bb76ff1Sjsg if (err)
1861bb76ff1Sjsg goto out_rq;
1871bb76ff1Sjsg
188f005ef32Sjsg len = emit_pte(rq, &it, pat_index, true, offset, CHUNK_SZ);
1891bb76ff1Sjsg if (len <= 0) {
1901bb76ff1Sjsg err = len;
1911bb76ff1Sjsg goto out_rq;
1921bb76ff1Sjsg }
1931bb76ff1Sjsg
1941bb76ff1Sjsg err = rq->engine->emit_flush(rq, EMIT_INVALIDATE);
1951bb76ff1Sjsg if (err)
1961bb76ff1Sjsg goto out_rq;
1971bb76ff1Sjsg
1981bb76ff1Sjsg err = emit_copy_ccs(rq, offset, dst_access,
1991bb76ff1Sjsg offset, src_access, len);
2001bb76ff1Sjsg if (err)
2011bb76ff1Sjsg goto out_rq;
2021bb76ff1Sjsg
2031bb76ff1Sjsg err = rq->engine->emit_flush(rq, EMIT_INVALIDATE);
2041bb76ff1Sjsg
2051bb76ff1Sjsg /* Arbitration is re-enabled between requests. */
2061bb76ff1Sjsg out_rq:
2071bb76ff1Sjsg if (*out)
2081bb76ff1Sjsg i915_request_put(*out);
2091bb76ff1Sjsg *out = i915_request_get(rq);
2101bb76ff1Sjsg i915_request_add(rq);
2111bb76ff1Sjsg if (err || !it.sg || !sg_dma_len(it.sg))
2121bb76ff1Sjsg break;
2131bb76ff1Sjsg
2141bb76ff1Sjsg cond_resched();
2151bb76ff1Sjsg } while (1);
2161bb76ff1Sjsg
2171bb76ff1Sjsg out_ce:
2181bb76ff1Sjsg return err;
2191bb76ff1Sjsg }
2201bb76ff1Sjsg
2211bb76ff1Sjsg static int
intel_migrate_ccs_copy(struct intel_migrate * m,struct i915_gem_ww_ctx * ww,const struct i915_deps * deps,struct scatterlist * sg,unsigned int pat_index,bool write_to_ccs,struct i915_request ** out)2221bb76ff1Sjsg intel_migrate_ccs_copy(struct intel_migrate *m,
2231bb76ff1Sjsg struct i915_gem_ww_ctx *ww,
2241bb76ff1Sjsg const struct i915_deps *deps,
2251bb76ff1Sjsg struct scatterlist *sg,
226f005ef32Sjsg unsigned int pat_index,
2271bb76ff1Sjsg bool write_to_ccs,
2281bb76ff1Sjsg struct i915_request **out)
2291bb76ff1Sjsg {
2301bb76ff1Sjsg struct intel_context *ce;
2311bb76ff1Sjsg int err;
2321bb76ff1Sjsg
2331bb76ff1Sjsg *out = NULL;
2341bb76ff1Sjsg if (!m->context)
2351bb76ff1Sjsg return -ENODEV;
2361bb76ff1Sjsg
2371bb76ff1Sjsg ce = intel_migrate_create_context(m);
2381bb76ff1Sjsg if (IS_ERR(ce))
2391bb76ff1Sjsg ce = intel_context_get(m->context);
2401bb76ff1Sjsg GEM_BUG_ON(IS_ERR(ce));
2411bb76ff1Sjsg
2421bb76ff1Sjsg err = intel_context_pin_ww(ce, ww);
2431bb76ff1Sjsg if (err)
2441bb76ff1Sjsg goto out;
2451bb76ff1Sjsg
246f005ef32Sjsg err = intel_context_copy_ccs(ce, deps, sg, pat_index,
2471bb76ff1Sjsg write_to_ccs, out);
2481bb76ff1Sjsg
2491bb76ff1Sjsg intel_context_unpin(ce);
2501bb76ff1Sjsg out:
2511bb76ff1Sjsg intel_context_put(ce);
2521bb76ff1Sjsg return err;
2531bb76ff1Sjsg }
2541bb76ff1Sjsg
clear(struct intel_migrate * migrate,int (* fn)(struct intel_migrate * migrate,struct i915_gem_ww_ctx * ww,struct drm_i915_gem_object * obj,u32 value,struct i915_request ** out),u32 sz,struct rnd_state * prng)2555ca02815Sjsg static int clear(struct intel_migrate *migrate,
2565ca02815Sjsg int (*fn)(struct intel_migrate *migrate,
2575ca02815Sjsg struct i915_gem_ww_ctx *ww,
2585ca02815Sjsg struct drm_i915_gem_object *obj,
2595ca02815Sjsg u32 value,
2605ca02815Sjsg struct i915_request **out),
2615ca02815Sjsg u32 sz, struct rnd_state *prng)
2625ca02815Sjsg {
2635ca02815Sjsg struct drm_i915_private *i915 = migrate->context->engine->i915;
2645ca02815Sjsg struct drm_i915_gem_object *obj;
2655ca02815Sjsg struct i915_request *rq;
2665ca02815Sjsg struct i915_gem_ww_ctx ww;
2671bb76ff1Sjsg u32 *vaddr, val = 0;
2681bb76ff1Sjsg bool ccs_cap = false;
2695ca02815Sjsg int err = 0;
2705ca02815Sjsg int i;
2715ca02815Sjsg
2725ca02815Sjsg obj = create_lmem_or_internal(i915, sz);
2735ca02815Sjsg if (IS_ERR(obj))
2745ca02815Sjsg return 0;
2755ca02815Sjsg
2761bb76ff1Sjsg /* Consider the rounded up memory too */
2771bb76ff1Sjsg sz = obj->base.size;
2781bb76ff1Sjsg
2791bb76ff1Sjsg if (HAS_FLAT_CCS(i915) && i915_gem_object_is_lmem(obj))
2801bb76ff1Sjsg ccs_cap = true;
2811bb76ff1Sjsg
2825ca02815Sjsg for_i915_gem_ww(&ww, err, true) {
2831bb76ff1Sjsg int ccs_bytes, ccs_bytes_per_chunk;
2841bb76ff1Sjsg
2855ca02815Sjsg err = i915_gem_object_lock(obj, &ww);
2865ca02815Sjsg if (err)
2875ca02815Sjsg continue;
2885ca02815Sjsg
2895ca02815Sjsg vaddr = i915_gem_object_pin_map(obj, I915_MAP_WC);
2905ca02815Sjsg if (IS_ERR(vaddr)) {
2915ca02815Sjsg err = PTR_ERR(vaddr);
2925ca02815Sjsg continue;
2935ca02815Sjsg }
2945ca02815Sjsg
2955ca02815Sjsg for (i = 0; i < sz / sizeof(u32); i++)
2965ca02815Sjsg vaddr[i] = ~i;
2975ca02815Sjsg i915_gem_object_flush_map(obj);
2985ca02815Sjsg
2991bb76ff1Sjsg if (ccs_cap && !val) {
3001bb76ff1Sjsg /* Write the obj data into ccs surface */
3011bb76ff1Sjsg err = intel_migrate_ccs_copy(migrate, &ww, NULL,
3021bb76ff1Sjsg obj->mm.pages->sgl,
303f005ef32Sjsg obj->pat_index,
3041bb76ff1Sjsg true, &rq);
3051bb76ff1Sjsg if (rq && !err) {
3061bb76ff1Sjsg if (i915_request_wait(rq, 0, HZ) < 0) {
3071bb76ff1Sjsg pr_err("%ps timed out, size: %u\n",
3081bb76ff1Sjsg fn, sz);
3091bb76ff1Sjsg err = -ETIME;
3105ca02815Sjsg }
3111bb76ff1Sjsg i915_request_put(rq);
3121bb76ff1Sjsg rq = NULL;
3135ca02815Sjsg }
3145ca02815Sjsg if (err)
3151bb76ff1Sjsg continue;
3161bb76ff1Sjsg }
3175ca02815Sjsg
3181bb76ff1Sjsg err = fn(migrate, &ww, obj, val, &rq);
3191bb76ff1Sjsg if (rq && !err) {
3205ca02815Sjsg if (i915_request_wait(rq, 0, HZ) < 0) {
3215ca02815Sjsg pr_err("%ps timed out, size: %u\n", fn, sz);
3225ca02815Sjsg err = -ETIME;
3235ca02815Sjsg }
3245ca02815Sjsg i915_request_put(rq);
3251bb76ff1Sjsg rq = NULL;
3265ca02815Sjsg }
3271bb76ff1Sjsg if (err)
3281bb76ff1Sjsg continue;
3295ca02815Sjsg
3301bb76ff1Sjsg i915_gem_object_flush_map(obj);
3311bb76ff1Sjsg
3321bb76ff1Sjsg /* Verify the set/clear of the obj mem */
3335ca02815Sjsg for (i = 0; !err && i < sz / PAGE_SIZE; i++) {
3341bb76ff1Sjsg int x = i * 1024 +
3351bb76ff1Sjsg i915_prandom_u32_max_state(1024, prng);
3365ca02815Sjsg
3371bb76ff1Sjsg if (vaddr[x] != val) {
3381bb76ff1Sjsg pr_err("%ps failed, (%u != %u), offset: %zu\n",
3391bb76ff1Sjsg fn, vaddr[x], val, x * sizeof(u32));
3405ca02815Sjsg igt_hexdump(vaddr + i * 1024, 4096);
3415ca02815Sjsg err = -EINVAL;
3425ca02815Sjsg }
3435ca02815Sjsg }
3441bb76ff1Sjsg if (err)
3451bb76ff1Sjsg continue;
3461bb76ff1Sjsg
3471bb76ff1Sjsg if (ccs_cap && !val) {
3481bb76ff1Sjsg for (i = 0; i < sz / sizeof(u32); i++)
3491bb76ff1Sjsg vaddr[i] = ~i;
3501bb76ff1Sjsg i915_gem_object_flush_map(obj);
3511bb76ff1Sjsg
3521bb76ff1Sjsg err = intel_migrate_ccs_copy(migrate, &ww, NULL,
3531bb76ff1Sjsg obj->mm.pages->sgl,
354f005ef32Sjsg obj->pat_index,
3551bb76ff1Sjsg false, &rq);
3561bb76ff1Sjsg if (rq && !err) {
3571bb76ff1Sjsg if (i915_request_wait(rq, 0, HZ) < 0) {
3581bb76ff1Sjsg pr_err("%ps timed out, size: %u\n",
3591bb76ff1Sjsg fn, sz);
3601bb76ff1Sjsg err = -ETIME;
3611bb76ff1Sjsg }
3621bb76ff1Sjsg i915_request_put(rq);
3631bb76ff1Sjsg rq = NULL;
3641bb76ff1Sjsg }
3651bb76ff1Sjsg if (err)
3661bb76ff1Sjsg continue;
3671bb76ff1Sjsg
3681bb76ff1Sjsg ccs_bytes = GET_CCS_BYTES(i915, sz);
3691bb76ff1Sjsg ccs_bytes_per_chunk = GET_CCS_BYTES(i915, CHUNK_SZ);
3701bb76ff1Sjsg i915_gem_object_flush_map(obj);
3711bb76ff1Sjsg
3721bb76ff1Sjsg for (i = 0; !err && i < DIV_ROUND_UP(ccs_bytes, PAGE_SIZE); i++) {
3731bb76ff1Sjsg int offset = ((i * PAGE_SIZE) /
3741bb76ff1Sjsg ccs_bytes_per_chunk) * CHUNK_SZ / sizeof(u32);
3751bb76ff1Sjsg int ccs_bytes_left = (ccs_bytes - i * PAGE_SIZE) / sizeof(u32);
3761bb76ff1Sjsg int x = i915_prandom_u32_max_state(min_t(int, 1024,
3771bb76ff1Sjsg ccs_bytes_left), prng);
3781bb76ff1Sjsg
3791bb76ff1Sjsg if (vaddr[offset + x]) {
3801bb76ff1Sjsg pr_err("%ps ccs clearing failed, offset: %ld/%d\n",
3811bb76ff1Sjsg fn, i * PAGE_SIZE + x * sizeof(u32), ccs_bytes);
3821bb76ff1Sjsg igt_hexdump(vaddr + offset,
3831bb76ff1Sjsg min_t(int, 4096,
3841bb76ff1Sjsg ccs_bytes_left * sizeof(u32)));
3851bb76ff1Sjsg err = -EINVAL;
3861bb76ff1Sjsg }
3871bb76ff1Sjsg }
3881bb76ff1Sjsg
3891bb76ff1Sjsg if (err)
3901bb76ff1Sjsg continue;
3911bb76ff1Sjsg }
3921bb76ff1Sjsg i915_gem_object_unpin_map(obj);
3931bb76ff1Sjsg }
3941bb76ff1Sjsg
3951bb76ff1Sjsg if (err) {
3961bb76ff1Sjsg if (err != -EDEADLK && err != -EINTR && err != -ERESTARTSYS)
3971bb76ff1Sjsg pr_err("%ps failed, size: %u\n", fn, sz);
3981bb76ff1Sjsg if (rq && err != -EINVAL) {
3991bb76ff1Sjsg i915_request_wait(rq, 0, HZ);
4001bb76ff1Sjsg i915_request_put(rq);
4011bb76ff1Sjsg }
4025ca02815Sjsg
4035ca02815Sjsg i915_gem_object_unpin_map(obj);
4041bb76ff1Sjsg }
4055ca02815Sjsg
4061bb76ff1Sjsg i915_gem_object_put(obj);
4075ca02815Sjsg return err;
4085ca02815Sjsg }
4095ca02815Sjsg
__migrate_copy(struct intel_migrate * migrate,struct i915_gem_ww_ctx * ww,struct drm_i915_gem_object * src,struct drm_i915_gem_object * dst,struct i915_request ** out)4105ca02815Sjsg static int __migrate_copy(struct intel_migrate *migrate,
4115ca02815Sjsg struct i915_gem_ww_ctx *ww,
4125ca02815Sjsg struct drm_i915_gem_object *src,
4135ca02815Sjsg struct drm_i915_gem_object *dst,
4145ca02815Sjsg struct i915_request **out)
4155ca02815Sjsg {
4165ca02815Sjsg return intel_migrate_copy(migrate, ww, NULL,
417f005ef32Sjsg src->mm.pages->sgl, src->pat_index,
4185ca02815Sjsg i915_gem_object_is_lmem(src),
419f005ef32Sjsg dst->mm.pages->sgl, dst->pat_index,
4205ca02815Sjsg i915_gem_object_is_lmem(dst),
4215ca02815Sjsg out);
4225ca02815Sjsg }
4235ca02815Sjsg
__global_copy(struct intel_migrate * migrate,struct i915_gem_ww_ctx * ww,struct drm_i915_gem_object * src,struct drm_i915_gem_object * dst,struct i915_request ** out)4245ca02815Sjsg static int __global_copy(struct intel_migrate *migrate,
4255ca02815Sjsg struct i915_gem_ww_ctx *ww,
4265ca02815Sjsg struct drm_i915_gem_object *src,
4275ca02815Sjsg struct drm_i915_gem_object *dst,
4285ca02815Sjsg struct i915_request **out)
4295ca02815Sjsg {
4305ca02815Sjsg return intel_context_migrate_copy(migrate->context, NULL,
431f005ef32Sjsg src->mm.pages->sgl, src->pat_index,
4325ca02815Sjsg i915_gem_object_is_lmem(src),
433f005ef32Sjsg dst->mm.pages->sgl, dst->pat_index,
4345ca02815Sjsg i915_gem_object_is_lmem(dst),
4355ca02815Sjsg out);
4365ca02815Sjsg }
4375ca02815Sjsg
4385ca02815Sjsg static int
migrate_copy(struct intel_migrate * migrate,u32 sz,struct rnd_state * prng)4395ca02815Sjsg migrate_copy(struct intel_migrate *migrate, u32 sz, struct rnd_state *prng)
4405ca02815Sjsg {
4415ca02815Sjsg return copy(migrate, __migrate_copy, sz, prng);
4425ca02815Sjsg }
4435ca02815Sjsg
4445ca02815Sjsg static int
global_copy(struct intel_migrate * migrate,u32 sz,struct rnd_state * prng)4455ca02815Sjsg global_copy(struct intel_migrate *migrate, u32 sz, struct rnd_state *prng)
4465ca02815Sjsg {
4475ca02815Sjsg return copy(migrate, __global_copy, sz, prng);
4485ca02815Sjsg }
4495ca02815Sjsg
__migrate_clear(struct intel_migrate * migrate,struct i915_gem_ww_ctx * ww,struct drm_i915_gem_object * obj,u32 value,struct i915_request ** out)4505ca02815Sjsg static int __migrate_clear(struct intel_migrate *migrate,
4515ca02815Sjsg struct i915_gem_ww_ctx *ww,
4525ca02815Sjsg struct drm_i915_gem_object *obj,
4535ca02815Sjsg u32 value,
4545ca02815Sjsg struct i915_request **out)
4555ca02815Sjsg {
4565ca02815Sjsg return intel_migrate_clear(migrate, ww, NULL,
4575ca02815Sjsg obj->mm.pages->sgl,
458f005ef32Sjsg obj->pat_index,
4595ca02815Sjsg i915_gem_object_is_lmem(obj),
4605ca02815Sjsg value, out);
4615ca02815Sjsg }
4625ca02815Sjsg
__global_clear(struct intel_migrate * migrate,struct i915_gem_ww_ctx * ww,struct drm_i915_gem_object * obj,u32 value,struct i915_request ** out)4635ca02815Sjsg static int __global_clear(struct intel_migrate *migrate,
4645ca02815Sjsg struct i915_gem_ww_ctx *ww,
4655ca02815Sjsg struct drm_i915_gem_object *obj,
4665ca02815Sjsg u32 value,
4675ca02815Sjsg struct i915_request **out)
4685ca02815Sjsg {
4695ca02815Sjsg return intel_context_migrate_clear(migrate->context, NULL,
4705ca02815Sjsg obj->mm.pages->sgl,
471f005ef32Sjsg obj->pat_index,
4725ca02815Sjsg i915_gem_object_is_lmem(obj),
4735ca02815Sjsg value, out);
4745ca02815Sjsg }
4755ca02815Sjsg
4765ca02815Sjsg static int
migrate_clear(struct intel_migrate * migrate,u32 sz,struct rnd_state * prng)4775ca02815Sjsg migrate_clear(struct intel_migrate *migrate, u32 sz, struct rnd_state *prng)
4785ca02815Sjsg {
4795ca02815Sjsg return clear(migrate, __migrate_clear, sz, prng);
4805ca02815Sjsg }
4815ca02815Sjsg
4825ca02815Sjsg static int
global_clear(struct intel_migrate * migrate,u32 sz,struct rnd_state * prng)4835ca02815Sjsg global_clear(struct intel_migrate *migrate, u32 sz, struct rnd_state *prng)
4845ca02815Sjsg {
4855ca02815Sjsg return clear(migrate, __global_clear, sz, prng);
4865ca02815Sjsg }
4875ca02815Sjsg
live_migrate_copy(void * arg)4885ca02815Sjsg static int live_migrate_copy(void *arg)
4895ca02815Sjsg {
490f005ef32Sjsg struct intel_gt *gt = arg;
491f005ef32Sjsg struct intel_migrate *migrate = >->migrate;
4925ca02815Sjsg struct drm_i915_private *i915 = migrate->context->engine->i915;
4935ca02815Sjsg I915_RND_STATE(prng);
4945ca02815Sjsg int i;
4955ca02815Sjsg
4965ca02815Sjsg for (i = 0; i < ARRAY_SIZE(sizes); i++) {
4975ca02815Sjsg int err;
4985ca02815Sjsg
4995ca02815Sjsg err = migrate_copy(migrate, sizes[i], &prng);
5005ca02815Sjsg if (err == 0)
5015ca02815Sjsg err = global_copy(migrate, sizes[i], &prng);
5025ca02815Sjsg i915_gem_drain_freed_objects(i915);
5035ca02815Sjsg if (err)
5045ca02815Sjsg return err;
5055ca02815Sjsg }
5065ca02815Sjsg
5075ca02815Sjsg return 0;
5085ca02815Sjsg }
5095ca02815Sjsg
live_migrate_clear(void * arg)5105ca02815Sjsg static int live_migrate_clear(void *arg)
5115ca02815Sjsg {
512f005ef32Sjsg struct intel_gt *gt = arg;
513f005ef32Sjsg struct intel_migrate *migrate = >->migrate;
5145ca02815Sjsg struct drm_i915_private *i915 = migrate->context->engine->i915;
5155ca02815Sjsg I915_RND_STATE(prng);
5165ca02815Sjsg int i;
5175ca02815Sjsg
5185ca02815Sjsg for (i = 0; i < ARRAY_SIZE(sizes); i++) {
5195ca02815Sjsg int err;
5205ca02815Sjsg
5215ca02815Sjsg err = migrate_clear(migrate, sizes[i], &prng);
5225ca02815Sjsg if (err == 0)
5235ca02815Sjsg err = global_clear(migrate, sizes[i], &prng);
5245ca02815Sjsg
5255ca02815Sjsg i915_gem_drain_freed_objects(i915);
5265ca02815Sjsg if (err)
5275ca02815Sjsg return err;
5285ca02815Sjsg }
5295ca02815Sjsg
5305ca02815Sjsg return 0;
5315ca02815Sjsg }
5325ca02815Sjsg
533f005ef32Sjsg struct spinner_timer {
534f005ef32Sjsg struct timer_list timer;
535f005ef32Sjsg struct igt_spinner spin;
536f005ef32Sjsg };
537f005ef32Sjsg
spinner_kill(struct timer_list * timer)538f005ef32Sjsg static void spinner_kill(struct timer_list *timer)
539f005ef32Sjsg {
540f005ef32Sjsg struct spinner_timer *st = from_timer(st, timer, timer);
541f005ef32Sjsg
542f005ef32Sjsg igt_spinner_end(&st->spin);
543f005ef32Sjsg pr_info("%s\n", __func__);
544f005ef32Sjsg }
545f005ef32Sjsg
live_emit_pte_full_ring(void * arg)546f005ef32Sjsg static int live_emit_pte_full_ring(void *arg)
547f005ef32Sjsg {
548f005ef32Sjsg struct intel_gt *gt = arg;
549f005ef32Sjsg struct intel_migrate *migrate = >->migrate;
550f005ef32Sjsg struct drm_i915_private *i915 = migrate->context->engine->i915;
551f005ef32Sjsg struct drm_i915_gem_object *obj;
552f005ef32Sjsg struct intel_context *ce;
553f005ef32Sjsg struct i915_request *rq, *prev;
554f005ef32Sjsg struct spinner_timer st;
555f005ef32Sjsg struct sgt_dma it;
556f005ef32Sjsg int len, sz, err;
557f005ef32Sjsg u32 *cs;
558f005ef32Sjsg
559f005ef32Sjsg /*
560f005ef32Sjsg * Simple regression test to check that we don't trample the
561f005ef32Sjsg * rq->reserved_space when returning from emit_pte(), if the ring is
562f005ef32Sjsg * nearly full.
563f005ef32Sjsg */
564f005ef32Sjsg
565f005ef32Sjsg if (igt_spinner_init(&st.spin, to_gt(i915)))
566f005ef32Sjsg return -ENOMEM;
567f005ef32Sjsg
568f005ef32Sjsg obj = i915_gem_object_create_internal(i915, 2 * PAGE_SIZE);
569f005ef32Sjsg if (IS_ERR(obj)) {
570f005ef32Sjsg err = PTR_ERR(obj);
571f005ef32Sjsg goto out_spinner;
572f005ef32Sjsg }
573f005ef32Sjsg
574f005ef32Sjsg err = i915_gem_object_pin_pages_unlocked(obj);
575f005ef32Sjsg if (err)
576f005ef32Sjsg goto out_obj;
577f005ef32Sjsg
578f005ef32Sjsg ce = intel_migrate_create_context(migrate);
579f005ef32Sjsg if (IS_ERR(ce)) {
580f005ef32Sjsg err = PTR_ERR(ce);
581f005ef32Sjsg goto out_obj;
582f005ef32Sjsg }
583f005ef32Sjsg
584f005ef32Sjsg ce->ring_size = SZ_4K; /* Not too big */
585f005ef32Sjsg
586f005ef32Sjsg err = intel_context_pin(ce);
587f005ef32Sjsg if (err)
588f005ef32Sjsg goto out_put;
589f005ef32Sjsg
590f005ef32Sjsg rq = igt_spinner_create_request(&st.spin, ce, MI_ARB_CHECK);
591f005ef32Sjsg if (IS_ERR(rq)) {
592f005ef32Sjsg err = PTR_ERR(rq);
593f005ef32Sjsg goto out_unpin;
594f005ef32Sjsg }
595f005ef32Sjsg
596f005ef32Sjsg i915_request_add(rq);
597f005ef32Sjsg if (!igt_wait_for_spinner(&st.spin, rq)) {
598f005ef32Sjsg err = -EIO;
599f005ef32Sjsg goto out_unpin;
600f005ef32Sjsg }
601f005ef32Sjsg
602f005ef32Sjsg /*
603f005ef32Sjsg * Fill the rest of the ring leaving I915_EMIT_PTE_NUM_DWORDS +
604f005ef32Sjsg * ring->reserved_space at the end. To actually emit the PTEs we require
605f005ef32Sjsg * slightly more than I915_EMIT_PTE_NUM_DWORDS, since our object size is
606f005ef32Sjsg * greater than PAGE_SIZE. The correct behaviour is to wait for more
607f005ef32Sjsg * ring space in emit_pte(), otherwise we trample on the reserved_space
608f005ef32Sjsg * resulting in crashes when later submitting the rq.
609f005ef32Sjsg */
610f005ef32Sjsg
611f005ef32Sjsg prev = NULL;
612f005ef32Sjsg do {
613f005ef32Sjsg if (prev)
614f005ef32Sjsg i915_request_add(rq);
615f005ef32Sjsg
616f005ef32Sjsg rq = i915_request_create(ce);
617f005ef32Sjsg if (IS_ERR(rq)) {
618f005ef32Sjsg err = PTR_ERR(rq);
619f005ef32Sjsg goto out_unpin;
620f005ef32Sjsg }
621f005ef32Sjsg
622f005ef32Sjsg sz = (rq->ring->space - rq->reserved_space) / sizeof(u32) -
623f005ef32Sjsg I915_EMIT_PTE_NUM_DWORDS;
624f005ef32Sjsg sz = min_t(u32, sz, (SZ_1K - rq->reserved_space) / sizeof(u32) -
625f005ef32Sjsg I915_EMIT_PTE_NUM_DWORDS);
626f005ef32Sjsg cs = intel_ring_begin(rq, sz);
627f005ef32Sjsg if (IS_ERR(cs)) {
628f005ef32Sjsg err = PTR_ERR(cs);
629f005ef32Sjsg goto out_rq;
630f005ef32Sjsg }
631f005ef32Sjsg
632f005ef32Sjsg memset32(cs, MI_NOOP, sz);
633f005ef32Sjsg cs += sz;
634f005ef32Sjsg intel_ring_advance(rq, cs);
635f005ef32Sjsg
636f005ef32Sjsg pr_info("%s emit=%u sz=%d\n", __func__, rq->ring->emit, sz);
637f005ef32Sjsg
638f005ef32Sjsg prev = rq;
639f005ef32Sjsg } while (rq->ring->space > (rq->reserved_space +
640f005ef32Sjsg I915_EMIT_PTE_NUM_DWORDS * sizeof(u32)));
641f005ef32Sjsg
642f005ef32Sjsg timer_setup_on_stack(&st.timer, spinner_kill, 0);
643f005ef32Sjsg mod_timer(&st.timer, jiffies + 2 * HZ);
644f005ef32Sjsg
645f005ef32Sjsg /*
646f005ef32Sjsg * This should wait for the spinner to be killed, otherwise we should go
647f005ef32Sjsg * down in flames when doing i915_request_add().
648f005ef32Sjsg */
649f005ef32Sjsg pr_info("%s emite_pte ring space=%u\n", __func__, rq->ring->space);
650f005ef32Sjsg it = sg_sgt(obj->mm.pages->sgl);
651f005ef32Sjsg len = emit_pte(rq, &it, obj->pat_index, false, 0, CHUNK_SZ);
652f005ef32Sjsg if (!len) {
653f005ef32Sjsg err = -EINVAL;
654f005ef32Sjsg goto out_rq;
655f005ef32Sjsg }
656f005ef32Sjsg if (len < 0) {
657f005ef32Sjsg err = len;
658f005ef32Sjsg goto out_rq;
659f005ef32Sjsg }
660f005ef32Sjsg
661f005ef32Sjsg out_rq:
662f005ef32Sjsg i915_request_add(rq); /* GEM_BUG_ON(rq->reserved_space > ring->space)? */
663f005ef32Sjsg del_timer_sync(&st.timer);
664f005ef32Sjsg destroy_timer_on_stack(&st.timer);
665f005ef32Sjsg out_unpin:
666f005ef32Sjsg intel_context_unpin(ce);
667f005ef32Sjsg out_put:
668f005ef32Sjsg intel_context_put(ce);
669f005ef32Sjsg out_obj:
670f005ef32Sjsg i915_gem_object_put(obj);
671f005ef32Sjsg out_spinner:
672f005ef32Sjsg igt_spinner_fini(&st.spin);
673f005ef32Sjsg return err;
674f005ef32Sjsg }
675f005ef32Sjsg
6765ca02815Sjsg struct threaded_migrate {
6775ca02815Sjsg struct intel_migrate *migrate;
6785ca02815Sjsg struct task_struct *tsk;
6795ca02815Sjsg struct rnd_state prng;
6805ca02815Sjsg };
6815ca02815Sjsg
threaded_migrate(struct intel_migrate * migrate,int (* fn)(void * arg),unsigned int flags)6825ca02815Sjsg static int threaded_migrate(struct intel_migrate *migrate,
6835ca02815Sjsg int (*fn)(void *arg),
6845ca02815Sjsg unsigned int flags)
6855ca02815Sjsg {
6865ca02815Sjsg const unsigned int n_cpus = num_online_cpus() + 1;
6875ca02815Sjsg struct threaded_migrate *thread;
6885ca02815Sjsg I915_RND_STATE(prng);
6895ca02815Sjsg unsigned int i;
6905ca02815Sjsg int err = 0;
6915ca02815Sjsg
6925ca02815Sjsg thread = kcalloc(n_cpus, sizeof(*thread), GFP_KERNEL);
6935ca02815Sjsg if (!thread)
6945ca02815Sjsg return 0;
6955ca02815Sjsg
6965ca02815Sjsg for (i = 0; i < n_cpus; ++i) {
6975ca02815Sjsg struct task_struct *tsk;
6985ca02815Sjsg
6995ca02815Sjsg thread[i].migrate = migrate;
7005ca02815Sjsg thread[i].prng =
7015ca02815Sjsg I915_RND_STATE_INITIALIZER(prandom_u32_state(&prng));
7025ca02815Sjsg
7035ca02815Sjsg tsk = kthread_run(fn, &thread[i], "igt-%d", i);
7045ca02815Sjsg if (IS_ERR(tsk)) {
7055ca02815Sjsg err = PTR_ERR(tsk);
7065ca02815Sjsg break;
7075ca02815Sjsg }
7085ca02815Sjsg
7095ca02815Sjsg get_task_struct(tsk);
7105ca02815Sjsg thread[i].tsk = tsk;
7115ca02815Sjsg }
7125ca02815Sjsg
7135ca02815Sjsg drm_msleep(10); /* start all threads before we kthread_stop() */
7145ca02815Sjsg
7155ca02815Sjsg for (i = 0; i < n_cpus; ++i) {
7165ca02815Sjsg struct task_struct *tsk = thread[i].tsk;
7175ca02815Sjsg int status;
7185ca02815Sjsg
7195ca02815Sjsg if (IS_ERR_OR_NULL(tsk))
7205ca02815Sjsg continue;
7215ca02815Sjsg
722*9cb8a68cSjsg status = kthread_stop_put(tsk);
7235ca02815Sjsg if (status && !err)
7245ca02815Sjsg err = status;
7255ca02815Sjsg }
7265ca02815Sjsg
7275ca02815Sjsg kfree(thread);
7285ca02815Sjsg return err;
7295ca02815Sjsg }
7305ca02815Sjsg
__thread_migrate_copy(void * arg)7315ca02815Sjsg static int __thread_migrate_copy(void *arg)
7325ca02815Sjsg {
7335ca02815Sjsg struct threaded_migrate *tm = arg;
7345ca02815Sjsg
7355ca02815Sjsg return migrate_copy(tm->migrate, 2 * CHUNK_SZ, &tm->prng);
7365ca02815Sjsg }
7375ca02815Sjsg
thread_migrate_copy(void * arg)7385ca02815Sjsg static int thread_migrate_copy(void *arg)
7395ca02815Sjsg {
740f005ef32Sjsg struct intel_gt *gt = arg;
741f005ef32Sjsg struct intel_migrate *migrate = >->migrate;
742f005ef32Sjsg
743f005ef32Sjsg return threaded_migrate(migrate, __thread_migrate_copy, 0);
7445ca02815Sjsg }
7455ca02815Sjsg
__thread_global_copy(void * arg)7465ca02815Sjsg static int __thread_global_copy(void *arg)
7475ca02815Sjsg {
7485ca02815Sjsg struct threaded_migrate *tm = arg;
7495ca02815Sjsg
7505ca02815Sjsg return global_copy(tm->migrate, 2 * CHUNK_SZ, &tm->prng);
7515ca02815Sjsg }
7525ca02815Sjsg
thread_global_copy(void * arg)7535ca02815Sjsg static int thread_global_copy(void *arg)
7545ca02815Sjsg {
755f005ef32Sjsg struct intel_gt *gt = arg;
756f005ef32Sjsg struct intel_migrate *migrate = >->migrate;
757f005ef32Sjsg
758f005ef32Sjsg return threaded_migrate(migrate, __thread_global_copy, 0);
7595ca02815Sjsg }
7605ca02815Sjsg
__thread_migrate_clear(void * arg)7615ca02815Sjsg static int __thread_migrate_clear(void *arg)
7625ca02815Sjsg {
7635ca02815Sjsg struct threaded_migrate *tm = arg;
7645ca02815Sjsg
7655ca02815Sjsg return migrate_clear(tm->migrate, 2 * CHUNK_SZ, &tm->prng);
7665ca02815Sjsg }
7675ca02815Sjsg
__thread_global_clear(void * arg)7685ca02815Sjsg static int __thread_global_clear(void *arg)
7695ca02815Sjsg {
7705ca02815Sjsg struct threaded_migrate *tm = arg;
7715ca02815Sjsg
7725ca02815Sjsg return global_clear(tm->migrate, 2 * CHUNK_SZ, &tm->prng);
7735ca02815Sjsg }
7745ca02815Sjsg
thread_migrate_clear(void * arg)7755ca02815Sjsg static int thread_migrate_clear(void *arg)
7765ca02815Sjsg {
777f005ef32Sjsg struct intel_gt *gt = arg;
778f005ef32Sjsg struct intel_migrate *migrate = >->migrate;
779f005ef32Sjsg
780f005ef32Sjsg return threaded_migrate(migrate, __thread_migrate_clear, 0);
7815ca02815Sjsg }
7825ca02815Sjsg
thread_global_clear(void * arg)7835ca02815Sjsg static int thread_global_clear(void *arg)
7845ca02815Sjsg {
785f005ef32Sjsg struct intel_gt *gt = arg;
786f005ef32Sjsg struct intel_migrate *migrate = >->migrate;
787f005ef32Sjsg
788f005ef32Sjsg return threaded_migrate(migrate, __thread_global_clear, 0);
7895ca02815Sjsg }
7905ca02815Sjsg
intel_migrate_live_selftests(struct drm_i915_private * i915)7915ca02815Sjsg int intel_migrate_live_selftests(struct drm_i915_private *i915)
7925ca02815Sjsg {
7935ca02815Sjsg static const struct i915_subtest tests[] = {
7945ca02815Sjsg SUBTEST(live_migrate_copy),
7955ca02815Sjsg SUBTEST(live_migrate_clear),
796f005ef32Sjsg SUBTEST(live_emit_pte_full_ring),
7975ca02815Sjsg SUBTEST(thread_migrate_copy),
7985ca02815Sjsg SUBTEST(thread_migrate_clear),
7995ca02815Sjsg SUBTEST(thread_global_copy),
8005ca02815Sjsg SUBTEST(thread_global_clear),
8015ca02815Sjsg };
8021bb76ff1Sjsg struct intel_gt *gt = to_gt(i915);
8035ca02815Sjsg
8045ca02815Sjsg if (!gt->migrate.context)
8055ca02815Sjsg return 0;
8065ca02815Sjsg
807f005ef32Sjsg return intel_gt_live_subtests(tests, gt);
8085ca02815Sjsg }
8095ca02815Sjsg
8105ca02815Sjsg static struct drm_i915_gem_object *
create_init_lmem_internal(struct intel_gt * gt,size_t sz,bool try_lmem)8115ca02815Sjsg create_init_lmem_internal(struct intel_gt *gt, size_t sz, bool try_lmem)
8125ca02815Sjsg {
8135ca02815Sjsg struct drm_i915_gem_object *obj = NULL;
8145ca02815Sjsg int err;
8155ca02815Sjsg
8165ca02815Sjsg if (try_lmem)
8175ca02815Sjsg obj = i915_gem_object_create_lmem(gt->i915, sz, 0);
8185ca02815Sjsg
8195ca02815Sjsg if (IS_ERR_OR_NULL(obj)) {
8205ca02815Sjsg obj = i915_gem_object_create_internal(gt->i915, sz);
8215ca02815Sjsg if (IS_ERR(obj))
8225ca02815Sjsg return obj;
8235ca02815Sjsg }
8245ca02815Sjsg
8251bb76ff1Sjsg i915_gem_object_trylock(obj, NULL);
8265ca02815Sjsg err = i915_gem_object_pin_pages(obj);
8275ca02815Sjsg if (err) {
8285ca02815Sjsg i915_gem_object_unlock(obj);
8295ca02815Sjsg i915_gem_object_put(obj);
8305ca02815Sjsg return ERR_PTR(err);
8315ca02815Sjsg }
8325ca02815Sjsg
8335ca02815Sjsg return obj;
8345ca02815Sjsg }
8355ca02815Sjsg
wrap_ktime_compare(const void * A,const void * B)8365ca02815Sjsg static int wrap_ktime_compare(const void *A, const void *B)
8375ca02815Sjsg {
8385ca02815Sjsg const ktime_t *a = A, *b = B;
8395ca02815Sjsg
8405ca02815Sjsg return ktime_compare(*a, *b);
8415ca02815Sjsg }
8425ca02815Sjsg
__perf_clear_blt(struct intel_context * ce,struct scatterlist * sg,unsigned int pat_index,bool is_lmem,size_t sz)8435ca02815Sjsg static int __perf_clear_blt(struct intel_context *ce,
8445ca02815Sjsg struct scatterlist *sg,
845f005ef32Sjsg unsigned int pat_index,
8465ca02815Sjsg bool is_lmem,
8475ca02815Sjsg size_t sz)
8485ca02815Sjsg {
8495ca02815Sjsg ktime_t t[5];
8505ca02815Sjsg int pass;
8515ca02815Sjsg int err = 0;
8525ca02815Sjsg
8535ca02815Sjsg for (pass = 0; pass < ARRAY_SIZE(t); pass++) {
8545ca02815Sjsg struct i915_request *rq;
8555ca02815Sjsg ktime_t t0, t1;
8565ca02815Sjsg
8575ca02815Sjsg t0 = ktime_get();
8585ca02815Sjsg
859f005ef32Sjsg err = intel_context_migrate_clear(ce, NULL, sg, pat_index,
8605ca02815Sjsg is_lmem, 0, &rq);
8615ca02815Sjsg if (rq) {
8625ca02815Sjsg if (i915_request_wait(rq, 0, MAX_SCHEDULE_TIMEOUT) < 0)
8635ca02815Sjsg err = -EIO;
8645ca02815Sjsg i915_request_put(rq);
8655ca02815Sjsg }
8665ca02815Sjsg if (err)
8675ca02815Sjsg break;
8685ca02815Sjsg
8695ca02815Sjsg t1 = ktime_get();
8705ca02815Sjsg t[pass] = ktime_sub(t1, t0);
8715ca02815Sjsg }
8725ca02815Sjsg if (err)
8735ca02815Sjsg return err;
8745ca02815Sjsg
8755ca02815Sjsg sort(t, ARRAY_SIZE(t), sizeof(*t), wrap_ktime_compare, NULL);
8765ca02815Sjsg pr_info("%s: %zd KiB fill: %lld MiB/s\n",
8775ca02815Sjsg ce->engine->name, sz >> 10,
8785ca02815Sjsg div64_u64(mul_u32_u32(4 * sz,
8795ca02815Sjsg 1000 * 1000 * 1000),
8805ca02815Sjsg t[1] + 2 * t[2] + t[3]) >> 20);
8815ca02815Sjsg return 0;
8825ca02815Sjsg }
8835ca02815Sjsg
perf_clear_blt(void * arg)8845ca02815Sjsg static int perf_clear_blt(void *arg)
8855ca02815Sjsg {
8865ca02815Sjsg struct intel_gt *gt = arg;
8875ca02815Sjsg static const unsigned long sizes[] = {
8885ca02815Sjsg SZ_4K,
8895ca02815Sjsg SZ_64K,
8905ca02815Sjsg SZ_2M,
8915ca02815Sjsg SZ_64M
8925ca02815Sjsg };
8935ca02815Sjsg int i;
8945ca02815Sjsg
8955ca02815Sjsg for (i = 0; i < ARRAY_SIZE(sizes); i++) {
8965ca02815Sjsg struct drm_i915_gem_object *dst;
8975ca02815Sjsg int err;
8985ca02815Sjsg
8995ca02815Sjsg dst = create_init_lmem_internal(gt, sizes[i], true);
9005ca02815Sjsg if (IS_ERR(dst))
9015ca02815Sjsg return PTR_ERR(dst);
9025ca02815Sjsg
9035ca02815Sjsg err = __perf_clear_blt(gt->migrate.context,
9045ca02815Sjsg dst->mm.pages->sgl,
905f005ef32Sjsg i915_gem_get_pat_index(gt->i915,
906f005ef32Sjsg I915_CACHE_NONE),
9075ca02815Sjsg i915_gem_object_is_lmem(dst),
9085ca02815Sjsg sizes[i]);
9095ca02815Sjsg
9105ca02815Sjsg i915_gem_object_unlock(dst);
9115ca02815Sjsg i915_gem_object_put(dst);
9125ca02815Sjsg if (err)
9135ca02815Sjsg return err;
9145ca02815Sjsg }
9155ca02815Sjsg
9165ca02815Sjsg return 0;
9175ca02815Sjsg }
9185ca02815Sjsg
__perf_copy_blt(struct intel_context * ce,struct scatterlist * src,unsigned int src_pat_index,bool src_is_lmem,struct scatterlist * dst,unsigned int dst_pat_index,bool dst_is_lmem,size_t sz)9195ca02815Sjsg static int __perf_copy_blt(struct intel_context *ce,
9205ca02815Sjsg struct scatterlist *src,
921f005ef32Sjsg unsigned int src_pat_index,
9225ca02815Sjsg bool src_is_lmem,
9235ca02815Sjsg struct scatterlist *dst,
924f005ef32Sjsg unsigned int dst_pat_index,
9255ca02815Sjsg bool dst_is_lmem,
9265ca02815Sjsg size_t sz)
9275ca02815Sjsg {
9285ca02815Sjsg ktime_t t[5];
9295ca02815Sjsg int pass;
9305ca02815Sjsg int err = 0;
9315ca02815Sjsg
9325ca02815Sjsg for (pass = 0; pass < ARRAY_SIZE(t); pass++) {
9335ca02815Sjsg struct i915_request *rq;
9345ca02815Sjsg ktime_t t0, t1;
9355ca02815Sjsg
9365ca02815Sjsg t0 = ktime_get();
9375ca02815Sjsg
9385ca02815Sjsg err = intel_context_migrate_copy(ce, NULL,
939f005ef32Sjsg src, src_pat_index,
9405ca02815Sjsg src_is_lmem,
941f005ef32Sjsg dst, dst_pat_index,
9425ca02815Sjsg dst_is_lmem,
9435ca02815Sjsg &rq);
9445ca02815Sjsg if (rq) {
9455ca02815Sjsg if (i915_request_wait(rq, 0, MAX_SCHEDULE_TIMEOUT) < 0)
9465ca02815Sjsg err = -EIO;
9475ca02815Sjsg i915_request_put(rq);
9485ca02815Sjsg }
9495ca02815Sjsg if (err)
9505ca02815Sjsg break;
9515ca02815Sjsg
9525ca02815Sjsg t1 = ktime_get();
9535ca02815Sjsg t[pass] = ktime_sub(t1, t0);
9545ca02815Sjsg }
9555ca02815Sjsg if (err)
9565ca02815Sjsg return err;
9575ca02815Sjsg
9585ca02815Sjsg sort(t, ARRAY_SIZE(t), sizeof(*t), wrap_ktime_compare, NULL);
9595ca02815Sjsg pr_info("%s: %zd KiB copy: %lld MiB/s\n",
9605ca02815Sjsg ce->engine->name, sz >> 10,
9615ca02815Sjsg div64_u64(mul_u32_u32(4 * sz,
9625ca02815Sjsg 1000 * 1000 * 1000),
9635ca02815Sjsg t[1] + 2 * t[2] + t[3]) >> 20);
9645ca02815Sjsg return 0;
9655ca02815Sjsg }
9665ca02815Sjsg
perf_copy_blt(void * arg)9675ca02815Sjsg static int perf_copy_blt(void *arg)
9685ca02815Sjsg {
9695ca02815Sjsg struct intel_gt *gt = arg;
9705ca02815Sjsg static const unsigned long sizes[] = {
9715ca02815Sjsg SZ_4K,
9725ca02815Sjsg SZ_64K,
9735ca02815Sjsg SZ_2M,
9745ca02815Sjsg SZ_64M
9755ca02815Sjsg };
9765ca02815Sjsg int i;
9775ca02815Sjsg
9785ca02815Sjsg for (i = 0; i < ARRAY_SIZE(sizes); i++) {
9795ca02815Sjsg struct drm_i915_gem_object *src, *dst;
9801bb76ff1Sjsg size_t sz;
9815ca02815Sjsg int err;
9825ca02815Sjsg
9835ca02815Sjsg src = create_init_lmem_internal(gt, sizes[i], true);
9845ca02815Sjsg if (IS_ERR(src))
9855ca02815Sjsg return PTR_ERR(src);
9865ca02815Sjsg
9871bb76ff1Sjsg sz = src->base.size;
9881bb76ff1Sjsg dst = create_init_lmem_internal(gt, sz, false);
9895ca02815Sjsg if (IS_ERR(dst)) {
9905ca02815Sjsg err = PTR_ERR(dst);
9915ca02815Sjsg goto err_src;
9925ca02815Sjsg }
9935ca02815Sjsg
9945ca02815Sjsg err = __perf_copy_blt(gt->migrate.context,
9955ca02815Sjsg src->mm.pages->sgl,
996f005ef32Sjsg i915_gem_get_pat_index(gt->i915,
997f005ef32Sjsg I915_CACHE_NONE),
9985ca02815Sjsg i915_gem_object_is_lmem(src),
9995ca02815Sjsg dst->mm.pages->sgl,
1000f005ef32Sjsg i915_gem_get_pat_index(gt->i915,
1001f005ef32Sjsg I915_CACHE_NONE),
10025ca02815Sjsg i915_gem_object_is_lmem(dst),
10031bb76ff1Sjsg sz);
10045ca02815Sjsg
10055ca02815Sjsg i915_gem_object_unlock(dst);
10065ca02815Sjsg i915_gem_object_put(dst);
10075ca02815Sjsg err_src:
10085ca02815Sjsg i915_gem_object_unlock(src);
10095ca02815Sjsg i915_gem_object_put(src);
10105ca02815Sjsg if (err)
10115ca02815Sjsg return err;
10125ca02815Sjsg }
10135ca02815Sjsg
10145ca02815Sjsg return 0;
10155ca02815Sjsg }
10165ca02815Sjsg
intel_migrate_perf_selftests(struct drm_i915_private * i915)10175ca02815Sjsg int intel_migrate_perf_selftests(struct drm_i915_private *i915)
10185ca02815Sjsg {
10195ca02815Sjsg static const struct i915_subtest tests[] = {
10205ca02815Sjsg SUBTEST(perf_clear_blt),
10215ca02815Sjsg SUBTEST(perf_copy_blt),
10225ca02815Sjsg };
10231bb76ff1Sjsg struct intel_gt *gt = to_gt(i915);
10245ca02815Sjsg
10255ca02815Sjsg if (intel_gt_is_wedged(gt))
10265ca02815Sjsg return 0;
10275ca02815Sjsg
10285ca02815Sjsg if (!gt->migrate.context)
10295ca02815Sjsg return 0;
10305ca02815Sjsg
10315ca02815Sjsg return intel_gt_live_subtests(tests, gt);
10325ca02815Sjsg }
1033