xref: /openbsd-src/sys/dev/pci/drm/i915/gt/selftest_migrate.c (revision 9cb8a68cefdfebdbaa33e2a501026c1d300ff582)
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 = &gt->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 = &gt->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 = &gt->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 = &gt->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 = &gt->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 = &gt->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 = &gt->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