xref: /openbmc/linux/drivers/gpu/drm/i915/gt/selftest_migrate.c (revision b181f7029bd71238ac2754ce7052dffd69432085)
1cf586021SChris Wilson // SPDX-License-Identifier: MIT
2cf586021SChris Wilson /*
3cf586021SChris Wilson  * Copyright © 2020 Intel Corporation
4cf586021SChris Wilson  */
5cf586021SChris Wilson 
694ce0d65SChris Wilson #include <linux/sort.h>
794ce0d65SChris Wilson 
8b508d01fSJani Nikula #include "gem/i915_gem_internal.h"
9d09aa852SJani Nikula #include "gem/i915_gem_lmem.h"
10b508d01fSJani Nikula 
11e288e178SMatthew Auld #include "selftests/igt_spinner.h"
12cf586021SChris Wilson #include "selftests/i915_random.h"
13cf586021SChris Wilson 
14cf586021SChris Wilson static const unsigned int sizes[] = {
15cf586021SChris Wilson 	SZ_4K,
16cf586021SChris Wilson 	SZ_64K,
17cf586021SChris Wilson 	SZ_2M,
18cf586021SChris Wilson 	CHUNK_SZ - SZ_4K,
19cf586021SChris Wilson 	CHUNK_SZ,
20cf586021SChris Wilson 	CHUNK_SZ + SZ_4K,
21cf586021SChris Wilson 	SZ_64M,
22cf586021SChris Wilson };
23cf586021SChris Wilson 
24cf586021SChris Wilson static struct drm_i915_gem_object *
create_lmem_or_internal(struct drm_i915_private * i915,size_t size)25cf586021SChris Wilson create_lmem_or_internal(struct drm_i915_private *i915, size_t size)
26cf586021SChris Wilson {
27cf586021SChris Wilson 	struct drm_i915_gem_object *obj;
28cf586021SChris Wilson 
29cf586021SChris Wilson 	obj = i915_gem_object_create_lmem(i915, size, 0);
30cf586021SChris Wilson 	if (!IS_ERR(obj))
31cf586021SChris Wilson 		return obj;
32cf586021SChris Wilson 
33cf586021SChris Wilson 	return i915_gem_object_create_internal(i915, size);
34cf586021SChris Wilson }
35cf586021SChris Wilson 
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)36cf586021SChris Wilson static int copy(struct intel_migrate *migrate,
37cf586021SChris Wilson 		int (*fn)(struct intel_migrate *migrate,
38cf586021SChris Wilson 			  struct i915_gem_ww_ctx *ww,
39cf586021SChris Wilson 			  struct drm_i915_gem_object *src,
40cf586021SChris Wilson 			  struct drm_i915_gem_object *dst,
41cf586021SChris Wilson 			  struct i915_request **out),
42cf586021SChris Wilson 		u32 sz, struct rnd_state *prng)
43cf586021SChris Wilson {
44cf586021SChris Wilson 	struct drm_i915_private *i915 = migrate->context->engine->i915;
45cf586021SChris Wilson 	struct drm_i915_gem_object *src, *dst;
46cf586021SChris Wilson 	struct i915_request *rq;
47cf586021SChris Wilson 	struct i915_gem_ww_ctx ww;
48cf586021SChris Wilson 	u32 *vaddr;
49cf586021SChris Wilson 	int err = 0;
50cf586021SChris Wilson 	int i;
51cf586021SChris Wilson 
52cf586021SChris Wilson 	src = create_lmem_or_internal(i915, sz);
53cf586021SChris Wilson 	if (IS_ERR(src))
54cf586021SChris Wilson 		return 0;
55cf586021SChris Wilson 
5697c8ef44SMatthew Auld 	sz = src->base.size;
57cf586021SChris Wilson 	dst = i915_gem_object_create_internal(i915, sz);
58cf586021SChris Wilson 	if (IS_ERR(dst))
59cf586021SChris Wilson 		goto err_free_src;
60cf586021SChris Wilson 
61cf586021SChris Wilson 	for_i915_gem_ww(&ww, err, true) {
62cf586021SChris Wilson 		err = i915_gem_object_lock(src, &ww);
63cf586021SChris Wilson 		if (err)
64cf586021SChris Wilson 			continue;
65cf586021SChris Wilson 
66cf586021SChris Wilson 		err = i915_gem_object_lock(dst, &ww);
67cf586021SChris Wilson 		if (err)
68cf586021SChris Wilson 			continue;
69cf586021SChris Wilson 
70cf586021SChris Wilson 		vaddr = i915_gem_object_pin_map(src, I915_MAP_WC);
71cf586021SChris Wilson 		if (IS_ERR(vaddr)) {
72cf586021SChris Wilson 			err = PTR_ERR(vaddr);
73cf586021SChris Wilson 			continue;
74cf586021SChris Wilson 		}
75cf586021SChris Wilson 
76cf586021SChris Wilson 		for (i = 0; i < sz / sizeof(u32); i++)
77cf586021SChris Wilson 			vaddr[i] = i;
78cf586021SChris Wilson 		i915_gem_object_flush_map(src);
79cf586021SChris Wilson 
80cf586021SChris Wilson 		vaddr = i915_gem_object_pin_map(dst, I915_MAP_WC);
81cf586021SChris Wilson 		if (IS_ERR(vaddr)) {
82cf586021SChris Wilson 			err = PTR_ERR(vaddr);
83cf586021SChris Wilson 			goto unpin_src;
84cf586021SChris Wilson 		}
85cf586021SChris Wilson 
86cf586021SChris Wilson 		for (i = 0; i < sz / sizeof(u32); i++)
87cf586021SChris Wilson 			vaddr[i] = ~i;
88cf586021SChris Wilson 		i915_gem_object_flush_map(dst);
89cf586021SChris Wilson 
90cf586021SChris Wilson 		err = fn(migrate, &ww, src, dst, &rq);
91cf586021SChris Wilson 		if (!err)
92cf586021SChris Wilson 			continue;
93cf586021SChris Wilson 
94cf586021SChris Wilson 		if (err != -EDEADLK && err != -EINTR && err != -ERESTARTSYS)
95cf586021SChris Wilson 			pr_err("%ps failed, size: %u\n", fn, sz);
96cf586021SChris Wilson 		if (rq) {
97cf586021SChris Wilson 			i915_request_wait(rq, 0, HZ);
98cf586021SChris Wilson 			i915_request_put(rq);
99cf586021SChris Wilson 		}
100cf586021SChris Wilson 		i915_gem_object_unpin_map(dst);
101cf586021SChris Wilson unpin_src:
102cf586021SChris Wilson 		i915_gem_object_unpin_map(src);
103cf586021SChris Wilson 	}
104cf586021SChris Wilson 	if (err)
105cf586021SChris Wilson 		goto err_out;
106cf586021SChris Wilson 
107cf586021SChris Wilson 	if (rq) {
108cf586021SChris Wilson 		if (i915_request_wait(rq, 0, HZ) < 0) {
109cf586021SChris Wilson 			pr_err("%ps timed out, size: %u\n", fn, sz);
110cf586021SChris Wilson 			err = -ETIME;
111cf586021SChris Wilson 		}
112cf586021SChris Wilson 		i915_request_put(rq);
113cf586021SChris Wilson 	}
114cf586021SChris Wilson 
115cf586021SChris Wilson 	for (i = 0; !err && i < sz / PAGE_SIZE; i++) {
116cf586021SChris Wilson 		int x = i * 1024 + i915_prandom_u32_max_state(1024, prng);
117cf586021SChris Wilson 
118cf586021SChris Wilson 		if (vaddr[x] != x) {
119cf586021SChris Wilson 			pr_err("%ps failed, size: %u, offset: %zu\n",
120cf586021SChris Wilson 			       fn, sz, x * sizeof(u32));
121cf586021SChris Wilson 			igt_hexdump(vaddr + i * 1024, 4096);
122cf586021SChris Wilson 			err = -EINVAL;
123cf586021SChris Wilson 		}
124cf586021SChris Wilson 	}
125cf586021SChris Wilson 
126cf586021SChris Wilson 	i915_gem_object_unpin_map(dst);
127cf586021SChris Wilson 	i915_gem_object_unpin_map(src);
128cf586021SChris Wilson 
129cf586021SChris Wilson err_out:
130cf586021SChris Wilson 	i915_gem_object_put(dst);
131cf586021SChris Wilson err_free_src:
132cf586021SChris Wilson 	i915_gem_object_put(src);
133cf586021SChris Wilson 
134cf586021SChris Wilson 	return err;
135cf586021SChris Wilson }
136cf586021SChris Wilson 
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)137c8f8a748SRamalingam C static int intel_context_copy_ccs(struct intel_context *ce,
138c8f8a748SRamalingam C 				  const struct i915_deps *deps,
139c8f8a748SRamalingam C 				  struct scatterlist *sg,
1409275277dSFei Yang 				  unsigned int pat_index,
141c8f8a748SRamalingam C 				  bool write_to_ccs,
142c8f8a748SRamalingam C 				  struct i915_request **out)
143c8f8a748SRamalingam C {
144c8f8a748SRamalingam C 	u8 src_access = write_to_ccs ? DIRECT_ACCESS : INDIRECT_ACCESS;
145c8f8a748SRamalingam C 	u8 dst_access = write_to_ccs ? INDIRECT_ACCESS : DIRECT_ACCESS;
146c8f8a748SRamalingam C 	struct sgt_dma it = sg_sgt(sg);
147c8f8a748SRamalingam C 	struct i915_request *rq;
148c8f8a748SRamalingam C 	u32 offset;
149c8f8a748SRamalingam C 	int err;
150c8f8a748SRamalingam C 
151c8f8a748SRamalingam C 	GEM_BUG_ON(ce->vm != ce->engine->gt->migrate.context->vm);
152c8f8a748SRamalingam C 	*out = NULL;
153c8f8a748SRamalingam C 
154c8f8a748SRamalingam C 	GEM_BUG_ON(ce->ring->size < SZ_64K);
155c8f8a748SRamalingam C 
156c8f8a748SRamalingam C 	offset = 0;
157c8f8a748SRamalingam C 	if (HAS_64K_PAGES(ce->engine->i915))
158c8f8a748SRamalingam C 		offset = CHUNK_SZ;
159c8f8a748SRamalingam C 
160c8f8a748SRamalingam C 	do {
161c8f8a748SRamalingam C 		int len;
162c8f8a748SRamalingam C 
163c8f8a748SRamalingam C 		rq = i915_request_create(ce);
164c8f8a748SRamalingam C 		if (IS_ERR(rq)) {
165c8f8a748SRamalingam C 			err = PTR_ERR(rq);
166c8f8a748SRamalingam C 			goto out_ce;
167c8f8a748SRamalingam C 		}
168c8f8a748SRamalingam C 
169c8f8a748SRamalingam C 		if (deps) {
170c8f8a748SRamalingam C 			err = i915_request_await_deps(rq, deps);
171c8f8a748SRamalingam C 			if (err)
172c8f8a748SRamalingam C 				goto out_rq;
173c8f8a748SRamalingam C 
174c8f8a748SRamalingam C 			if (rq->engine->emit_init_breadcrumb) {
175c8f8a748SRamalingam C 				err = rq->engine->emit_init_breadcrumb(rq);
176c8f8a748SRamalingam C 				if (err)
177c8f8a748SRamalingam C 					goto out_rq;
178c8f8a748SRamalingam C 			}
179c8f8a748SRamalingam C 
180c8f8a748SRamalingam C 			deps = NULL;
181c8f8a748SRamalingam C 		}
182c8f8a748SRamalingam C 
183c8f8a748SRamalingam C 		/* The PTE updates + clear must not be interrupted. */
184c8f8a748SRamalingam C 		err = emit_no_arbitration(rq);
185c8f8a748SRamalingam C 		if (err)
186c8f8a748SRamalingam C 			goto out_rq;
187c8f8a748SRamalingam C 
1889275277dSFei Yang 		len = emit_pte(rq, &it, pat_index, true, offset, CHUNK_SZ);
189c8f8a748SRamalingam C 		if (len <= 0) {
190c8f8a748SRamalingam C 			err = len;
191c8f8a748SRamalingam C 			goto out_rq;
192c8f8a748SRamalingam C 		}
193c8f8a748SRamalingam C 
194c8f8a748SRamalingam C 		err = rq->engine->emit_flush(rq, EMIT_INVALIDATE);
195c8f8a748SRamalingam C 		if (err)
196c8f8a748SRamalingam C 			goto out_rq;
197c8f8a748SRamalingam C 
198c8f8a748SRamalingam C 		err = emit_copy_ccs(rq, offset, dst_access,
199c8f8a748SRamalingam C 				    offset, src_access, len);
200c8f8a748SRamalingam C 		if (err)
201c8f8a748SRamalingam C 			goto out_rq;
202c8f8a748SRamalingam C 
203c8f8a748SRamalingam C 		err = rq->engine->emit_flush(rq, EMIT_INVALIDATE);
204c8f8a748SRamalingam C 
205c8f8a748SRamalingam C 		/* Arbitration is re-enabled between requests. */
206c8f8a748SRamalingam C out_rq:
207c8f8a748SRamalingam C 		if (*out)
208c8f8a748SRamalingam C 			i915_request_put(*out);
209c8f8a748SRamalingam C 		*out = i915_request_get(rq);
210c8f8a748SRamalingam C 		i915_request_add(rq);
211c8f8a748SRamalingam C 		if (err || !it.sg || !sg_dma_len(it.sg))
212c8f8a748SRamalingam C 			break;
213c8f8a748SRamalingam C 
214c8f8a748SRamalingam C 		cond_resched();
215c8f8a748SRamalingam C 	} while (1);
216c8f8a748SRamalingam C 
217c8f8a748SRamalingam C out_ce:
218c8f8a748SRamalingam C 	return err;
219c8f8a748SRamalingam C }
220c8f8a748SRamalingam C 
221c8f8a748SRamalingam C 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)222c8f8a748SRamalingam C intel_migrate_ccs_copy(struct intel_migrate *m,
223c8f8a748SRamalingam C 		       struct i915_gem_ww_ctx *ww,
224c8f8a748SRamalingam C 		       const struct i915_deps *deps,
225c8f8a748SRamalingam C 		       struct scatterlist *sg,
2269275277dSFei Yang 		       unsigned int pat_index,
227c8f8a748SRamalingam C 		       bool write_to_ccs,
228c8f8a748SRamalingam C 		       struct i915_request **out)
229c8f8a748SRamalingam C {
230c8f8a748SRamalingam C 	struct intel_context *ce;
231c8f8a748SRamalingam C 	int err;
232c8f8a748SRamalingam C 
233c8f8a748SRamalingam C 	*out = NULL;
234c8f8a748SRamalingam C 	if (!m->context)
235c8f8a748SRamalingam C 		return -ENODEV;
236c8f8a748SRamalingam C 
237c8f8a748SRamalingam C 	ce = intel_migrate_create_context(m);
238c8f8a748SRamalingam C 	if (IS_ERR(ce))
239c8f8a748SRamalingam C 		ce = intel_context_get(m->context);
240c8f8a748SRamalingam C 	GEM_BUG_ON(IS_ERR(ce));
241c8f8a748SRamalingam C 
242c8f8a748SRamalingam C 	err = intel_context_pin_ww(ce, ww);
243c8f8a748SRamalingam C 	if (err)
244c8f8a748SRamalingam C 		goto out;
245c8f8a748SRamalingam C 
2469275277dSFei Yang 	err = intel_context_copy_ccs(ce, deps, sg, pat_index,
247c8f8a748SRamalingam C 				     write_to_ccs, out);
248c8f8a748SRamalingam C 
249c8f8a748SRamalingam C 	intel_context_unpin(ce);
250c8f8a748SRamalingam C out:
251c8f8a748SRamalingam C 	intel_context_put(ce);
252c8f8a748SRamalingam C 	return err;
253c8f8a748SRamalingam C }
254c8f8a748SRamalingam C 
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)255563baae1SChris Wilson static int clear(struct intel_migrate *migrate,
256563baae1SChris Wilson 		 int (*fn)(struct intel_migrate *migrate,
257563baae1SChris Wilson 			   struct i915_gem_ww_ctx *ww,
258563baae1SChris Wilson 			   struct drm_i915_gem_object *obj,
259563baae1SChris Wilson 			   u32 value,
260563baae1SChris Wilson 			   struct i915_request **out),
261563baae1SChris Wilson 		 u32 sz, struct rnd_state *prng)
262563baae1SChris Wilson {
263563baae1SChris Wilson 	struct drm_i915_private *i915 = migrate->context->engine->i915;
264563baae1SChris Wilson 	struct drm_i915_gem_object *obj;
265563baae1SChris Wilson 	struct i915_request *rq;
266563baae1SChris Wilson 	struct i915_gem_ww_ctx ww;
267c8f8a748SRamalingam C 	u32 *vaddr, val = 0;
268c8f8a748SRamalingam C 	bool ccs_cap = false;
269563baae1SChris Wilson 	int err = 0;
270563baae1SChris Wilson 	int i;
271563baae1SChris Wilson 
272563baae1SChris Wilson 	obj = create_lmem_or_internal(i915, sz);
273563baae1SChris Wilson 	if (IS_ERR(obj))
274563baae1SChris Wilson 		return 0;
275563baae1SChris Wilson 
276a785d3a8SRamalingam C 	/* Consider the rounded up memory too */
277a785d3a8SRamalingam C 	sz = obj->base.size;
278a785d3a8SRamalingam C 
279c8f8a748SRamalingam C 	if (HAS_FLAT_CCS(i915) && i915_gem_object_is_lmem(obj))
280c8f8a748SRamalingam C 		ccs_cap = true;
281c8f8a748SRamalingam C 
282563baae1SChris Wilson 	for_i915_gem_ww(&ww, err, true) {
283c8f8a748SRamalingam C 		int ccs_bytes, ccs_bytes_per_chunk;
284c8f8a748SRamalingam C 
285563baae1SChris Wilson 		err = i915_gem_object_lock(obj, &ww);
286563baae1SChris Wilson 		if (err)
287563baae1SChris Wilson 			continue;
288563baae1SChris Wilson 
289563baae1SChris Wilson 		vaddr = i915_gem_object_pin_map(obj, I915_MAP_WC);
290563baae1SChris Wilson 		if (IS_ERR(vaddr)) {
291563baae1SChris Wilson 			err = PTR_ERR(vaddr);
292563baae1SChris Wilson 			continue;
293563baae1SChris Wilson 		}
294563baae1SChris Wilson 
295563baae1SChris Wilson 		for (i = 0; i < sz / sizeof(u32); i++)
296563baae1SChris Wilson 			vaddr[i] = ~i;
297563baae1SChris Wilson 		i915_gem_object_flush_map(obj);
298563baae1SChris Wilson 
299c8f8a748SRamalingam C 		if (ccs_cap && !val) {
300c8f8a748SRamalingam C 			/* Write the obj data into ccs surface */
301c8f8a748SRamalingam C 			err = intel_migrate_ccs_copy(migrate, &ww, NULL,
302c8f8a748SRamalingam C 						     obj->mm.pages->sgl,
3039275277dSFei Yang 						     obj->pat_index,
304c8f8a748SRamalingam C 						     true, &rq);
305c8f8a748SRamalingam C 			if (rq && !err) {
306c8f8a748SRamalingam C 				if (i915_request_wait(rq, 0, HZ) < 0) {
307c8f8a748SRamalingam C 					pr_err("%ps timed out, size: %u\n",
308c8f8a748SRamalingam C 					       fn, sz);
309c8f8a748SRamalingam C 					err = -ETIME;
310563baae1SChris Wilson 				}
311c8f8a748SRamalingam C 				i915_request_put(rq);
312c8f8a748SRamalingam C 				rq = NULL;
313563baae1SChris Wilson 			}
314563baae1SChris Wilson 			if (err)
315c8f8a748SRamalingam C 				continue;
316c8f8a748SRamalingam C 		}
317563baae1SChris Wilson 
318c8f8a748SRamalingam C 		err = fn(migrate, &ww, obj, val, &rq);
319c8f8a748SRamalingam C 		if (rq && !err) {
320563baae1SChris Wilson 			if (i915_request_wait(rq, 0, HZ) < 0) {
321563baae1SChris Wilson 				pr_err("%ps timed out, size: %u\n", fn, sz);
322563baae1SChris Wilson 				err = -ETIME;
323563baae1SChris Wilson 			}
324563baae1SChris Wilson 			i915_request_put(rq);
325c8f8a748SRamalingam C 			rq = NULL;
326563baae1SChris Wilson 		}
327c8f8a748SRamalingam C 		if (err)
328c8f8a748SRamalingam C 			continue;
329563baae1SChris Wilson 
330c8f8a748SRamalingam C 		i915_gem_object_flush_map(obj);
331c8f8a748SRamalingam C 
332c8f8a748SRamalingam C 		/* Verify the set/clear of the obj mem */
333563baae1SChris Wilson 		for (i = 0; !err && i < sz / PAGE_SIZE; i++) {
334c8f8a748SRamalingam C 			int x = i * 1024 +
335c8f8a748SRamalingam C 				i915_prandom_u32_max_state(1024, prng);
336563baae1SChris Wilson 
337c8f8a748SRamalingam C 			if (vaddr[x] != val) {
338c8f8a748SRamalingam C 				pr_err("%ps failed, (%u != %u), offset: %zu\n",
339c8f8a748SRamalingam C 				       fn, vaddr[x], val,  x * sizeof(u32));
340563baae1SChris Wilson 				igt_hexdump(vaddr + i * 1024, 4096);
341563baae1SChris Wilson 				err = -EINVAL;
342563baae1SChris Wilson 			}
343563baae1SChris Wilson 		}
344c8f8a748SRamalingam C 		if (err)
345c8f8a748SRamalingam C 			continue;
346c8f8a748SRamalingam C 
347c8f8a748SRamalingam C 		if (ccs_cap && !val) {
348c8f8a748SRamalingam C 			for (i = 0; i < sz / sizeof(u32); i++)
349c8f8a748SRamalingam C 				vaddr[i] = ~i;
350c8f8a748SRamalingam C 			i915_gem_object_flush_map(obj);
351c8f8a748SRamalingam C 
352c8f8a748SRamalingam C 			err = intel_migrate_ccs_copy(migrate, &ww, NULL,
353c8f8a748SRamalingam C 						     obj->mm.pages->sgl,
3549275277dSFei Yang 						     obj->pat_index,
355c8f8a748SRamalingam C 						     false, &rq);
356c8f8a748SRamalingam C 			if (rq && !err) {
357c8f8a748SRamalingam C 				if (i915_request_wait(rq, 0, HZ) < 0) {
358c8f8a748SRamalingam C 					pr_err("%ps timed out, size: %u\n",
359c8f8a748SRamalingam C 					       fn, sz);
360c8f8a748SRamalingam C 					err = -ETIME;
361c8f8a748SRamalingam C 				}
362c8f8a748SRamalingam C 				i915_request_put(rq);
363c8f8a748SRamalingam C 				rq = NULL;
364c8f8a748SRamalingam C 			}
365c8f8a748SRamalingam C 			if (err)
366c8f8a748SRamalingam C 				continue;
367c8f8a748SRamalingam C 
368c8f8a748SRamalingam C 			ccs_bytes = GET_CCS_BYTES(i915, sz);
369c8f8a748SRamalingam C 			ccs_bytes_per_chunk = GET_CCS_BYTES(i915, CHUNK_SZ);
370c8f8a748SRamalingam C 			i915_gem_object_flush_map(obj);
371c8f8a748SRamalingam C 
372c8f8a748SRamalingam C 			for (i = 0; !err && i < DIV_ROUND_UP(ccs_bytes, PAGE_SIZE); i++) {
373c8f8a748SRamalingam C 				int offset = ((i * PAGE_SIZE)  /
374c8f8a748SRamalingam C 					ccs_bytes_per_chunk) * CHUNK_SZ / sizeof(u32);
375c8f8a748SRamalingam C 				int ccs_bytes_left = (ccs_bytes - i * PAGE_SIZE) / sizeof(u32);
376c8f8a748SRamalingam C 				int x = i915_prandom_u32_max_state(min_t(int, 1024,
377c8f8a748SRamalingam C 									 ccs_bytes_left), prng);
378c8f8a748SRamalingam C 
379c8f8a748SRamalingam C 				if (vaddr[offset + x]) {
380c8f8a748SRamalingam C 					pr_err("%ps ccs clearing failed, offset: %ld/%d\n",
381c8f8a748SRamalingam C 					       fn, i * PAGE_SIZE + x * sizeof(u32), ccs_bytes);
382c8f8a748SRamalingam C 					igt_hexdump(vaddr + offset,
383c8f8a748SRamalingam C 						    min_t(int, 4096,
384c8f8a748SRamalingam C 							  ccs_bytes_left * sizeof(u32)));
385c8f8a748SRamalingam C 					err = -EINVAL;
386c8f8a748SRamalingam C 				}
387c8f8a748SRamalingam C 			}
388c8f8a748SRamalingam C 
389c8f8a748SRamalingam C 			if (err)
390c8f8a748SRamalingam C 				continue;
391c8f8a748SRamalingam C 		}
392c8f8a748SRamalingam C 		i915_gem_object_unpin_map(obj);
393c8f8a748SRamalingam C 	}
394c8f8a748SRamalingam C 
395c8f8a748SRamalingam C 	if (err) {
396c8f8a748SRamalingam C 		if (err != -EDEADLK && err != -EINTR && err != -ERESTARTSYS)
397c8f8a748SRamalingam C 			pr_err("%ps failed, size: %u\n", fn, sz);
398c8f8a748SRamalingam C 		if (rq && err != -EINVAL) {
399c8f8a748SRamalingam C 			i915_request_wait(rq, 0, HZ);
400c8f8a748SRamalingam C 			i915_request_put(rq);
401c8f8a748SRamalingam C 		}
402563baae1SChris Wilson 
403563baae1SChris Wilson 		i915_gem_object_unpin_map(obj);
404c8f8a748SRamalingam C 	}
405563baae1SChris Wilson 
406c8f8a748SRamalingam C 	i915_gem_object_put(obj);
407563baae1SChris Wilson 	return err;
408563baae1SChris Wilson }
409563baae1SChris Wilson 
__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)410cf586021SChris Wilson static int __migrate_copy(struct intel_migrate *migrate,
411cf586021SChris Wilson 			  struct i915_gem_ww_ctx *ww,
412cf586021SChris Wilson 			  struct drm_i915_gem_object *src,
413cf586021SChris Wilson 			  struct drm_i915_gem_object *dst,
414cf586021SChris Wilson 			  struct i915_request **out)
415cf586021SChris Wilson {
416cf586021SChris Wilson 	return intel_migrate_copy(migrate, ww, NULL,
4179275277dSFei Yang 				  src->mm.pages->sgl, src->pat_index,
418cf586021SChris Wilson 				  i915_gem_object_is_lmem(src),
4199275277dSFei Yang 				  dst->mm.pages->sgl, dst->pat_index,
420cf586021SChris Wilson 				  i915_gem_object_is_lmem(dst),
421cf586021SChris Wilson 				  out);
422cf586021SChris Wilson }
423cf586021SChris Wilson 
__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)424cf586021SChris Wilson static int __global_copy(struct intel_migrate *migrate,
425cf586021SChris Wilson 			 struct i915_gem_ww_ctx *ww,
426cf586021SChris Wilson 			 struct drm_i915_gem_object *src,
427cf586021SChris Wilson 			 struct drm_i915_gem_object *dst,
428cf586021SChris Wilson 			 struct i915_request **out)
429cf586021SChris Wilson {
430cf586021SChris Wilson 	return intel_context_migrate_copy(migrate->context, NULL,
4319275277dSFei Yang 					  src->mm.pages->sgl, src->pat_index,
432cf586021SChris Wilson 					  i915_gem_object_is_lmem(src),
4339275277dSFei Yang 					  dst->mm.pages->sgl, dst->pat_index,
434cf586021SChris Wilson 					  i915_gem_object_is_lmem(dst),
435cf586021SChris Wilson 					  out);
436cf586021SChris Wilson }
437cf586021SChris Wilson 
438cf586021SChris Wilson static int
migrate_copy(struct intel_migrate * migrate,u32 sz,struct rnd_state * prng)439cf586021SChris Wilson migrate_copy(struct intel_migrate *migrate, u32 sz, struct rnd_state *prng)
440cf586021SChris Wilson {
441cf586021SChris Wilson 	return copy(migrate, __migrate_copy, sz, prng);
442cf586021SChris Wilson }
443cf586021SChris Wilson 
444cf586021SChris Wilson static int
global_copy(struct intel_migrate * migrate,u32 sz,struct rnd_state * prng)445cf586021SChris Wilson global_copy(struct intel_migrate *migrate, u32 sz, struct rnd_state *prng)
446cf586021SChris Wilson {
447cf586021SChris Wilson 	return copy(migrate, __global_copy, sz, prng);
448cf586021SChris Wilson }
449cf586021SChris Wilson 
__migrate_clear(struct intel_migrate * migrate,struct i915_gem_ww_ctx * ww,struct drm_i915_gem_object * obj,u32 value,struct i915_request ** out)450563baae1SChris Wilson static int __migrate_clear(struct intel_migrate *migrate,
451563baae1SChris Wilson 			   struct i915_gem_ww_ctx *ww,
452563baae1SChris Wilson 			   struct drm_i915_gem_object *obj,
453563baae1SChris Wilson 			   u32 value,
454563baae1SChris Wilson 			   struct i915_request **out)
455563baae1SChris Wilson {
456563baae1SChris Wilson 	return intel_migrate_clear(migrate, ww, NULL,
457563baae1SChris Wilson 				   obj->mm.pages->sgl,
4589275277dSFei Yang 				   obj->pat_index,
459563baae1SChris Wilson 				   i915_gem_object_is_lmem(obj),
460563baae1SChris Wilson 				   value, out);
461563baae1SChris Wilson }
462563baae1SChris Wilson 
__global_clear(struct intel_migrate * migrate,struct i915_gem_ww_ctx * ww,struct drm_i915_gem_object * obj,u32 value,struct i915_request ** out)463563baae1SChris Wilson static int __global_clear(struct intel_migrate *migrate,
464563baae1SChris Wilson 			  struct i915_gem_ww_ctx *ww,
465563baae1SChris Wilson 			  struct drm_i915_gem_object *obj,
466563baae1SChris Wilson 			  u32 value,
467563baae1SChris Wilson 			  struct i915_request **out)
468563baae1SChris Wilson {
469563baae1SChris Wilson 	return intel_context_migrate_clear(migrate->context, NULL,
470563baae1SChris Wilson 					   obj->mm.pages->sgl,
4719275277dSFei Yang 					   obj->pat_index,
472563baae1SChris Wilson 					   i915_gem_object_is_lmem(obj),
473563baae1SChris Wilson 					   value, out);
474563baae1SChris Wilson }
475563baae1SChris Wilson 
476563baae1SChris Wilson static int
migrate_clear(struct intel_migrate * migrate,u32 sz,struct rnd_state * prng)477563baae1SChris Wilson migrate_clear(struct intel_migrate *migrate, u32 sz, struct rnd_state *prng)
478563baae1SChris Wilson {
479563baae1SChris Wilson 	return clear(migrate, __migrate_clear, sz, prng);
480563baae1SChris Wilson }
481563baae1SChris Wilson 
482563baae1SChris Wilson static int
global_clear(struct intel_migrate * migrate,u32 sz,struct rnd_state * prng)483563baae1SChris Wilson global_clear(struct intel_migrate *migrate, u32 sz, struct rnd_state *prng)
484563baae1SChris Wilson {
485563baae1SChris Wilson 	return clear(migrate, __global_clear, sz, prng);
486563baae1SChris Wilson }
487563baae1SChris Wilson 
live_migrate_copy(void * arg)488cf586021SChris Wilson static int live_migrate_copy(void *arg)
489cf586021SChris Wilson {
490f7f0ca57SMatthew Auld 	struct intel_gt *gt = arg;
491f7f0ca57SMatthew Auld 	struct intel_migrate *migrate = &gt->migrate;
492cf586021SChris Wilson 	struct drm_i915_private *i915 = migrate->context->engine->i915;
493cf586021SChris Wilson 	I915_RND_STATE(prng);
494cf586021SChris Wilson 	int i;
495cf586021SChris Wilson 
496cf586021SChris Wilson 	for (i = 0; i < ARRAY_SIZE(sizes); i++) {
497cf586021SChris Wilson 		int err;
498cf586021SChris Wilson 
499cf586021SChris Wilson 		err = migrate_copy(migrate, sizes[i], &prng);
500cf586021SChris Wilson 		if (err == 0)
501cf586021SChris Wilson 			err = global_copy(migrate, sizes[i], &prng);
502cf586021SChris Wilson 		i915_gem_drain_freed_objects(i915);
503cf586021SChris Wilson 		if (err)
504cf586021SChris Wilson 			return err;
505cf586021SChris Wilson 	}
506cf586021SChris Wilson 
507cf586021SChris Wilson 	return 0;
508cf586021SChris Wilson }
509cf586021SChris Wilson 
live_migrate_clear(void * arg)510563baae1SChris Wilson static int live_migrate_clear(void *arg)
511563baae1SChris Wilson {
512f7f0ca57SMatthew Auld 	struct intel_gt *gt = arg;
513f7f0ca57SMatthew Auld 	struct intel_migrate *migrate = &gt->migrate;
514563baae1SChris Wilson 	struct drm_i915_private *i915 = migrate->context->engine->i915;
515563baae1SChris Wilson 	I915_RND_STATE(prng);
516563baae1SChris Wilson 	int i;
517563baae1SChris Wilson 
518563baae1SChris Wilson 	for (i = 0; i < ARRAY_SIZE(sizes); i++) {
519563baae1SChris Wilson 		int err;
520563baae1SChris Wilson 
521563baae1SChris Wilson 		err = migrate_clear(migrate, sizes[i], &prng);
522563baae1SChris Wilson 		if (err == 0)
523563baae1SChris Wilson 			err = global_clear(migrate, sizes[i], &prng);
524563baae1SChris Wilson 
525563baae1SChris Wilson 		i915_gem_drain_freed_objects(i915);
526563baae1SChris Wilson 		if (err)
527563baae1SChris Wilson 			return err;
528563baae1SChris Wilson 	}
529563baae1SChris Wilson 
530563baae1SChris Wilson 	return 0;
531563baae1SChris Wilson }
532563baae1SChris Wilson 
533e288e178SMatthew Auld struct spinner_timer {
534e288e178SMatthew Auld 	struct timer_list timer;
535e288e178SMatthew Auld 	struct igt_spinner spin;
536e288e178SMatthew Auld };
537e288e178SMatthew Auld 
spinner_kill(struct timer_list * timer)538e288e178SMatthew Auld static void spinner_kill(struct timer_list *timer)
539e288e178SMatthew Auld {
540e288e178SMatthew Auld 	struct spinner_timer *st = from_timer(st, timer, timer);
541e288e178SMatthew Auld 
542e288e178SMatthew Auld 	igt_spinner_end(&st->spin);
543e288e178SMatthew Auld 	pr_info("%s\n", __func__);
544e288e178SMatthew Auld }
545e288e178SMatthew Auld 
live_emit_pte_full_ring(void * arg)546e288e178SMatthew Auld static int live_emit_pte_full_ring(void *arg)
547e288e178SMatthew Auld {
548e288e178SMatthew Auld 	struct intel_gt *gt = arg;
549e288e178SMatthew Auld 	struct intel_migrate *migrate = &gt->migrate;
550e288e178SMatthew Auld 	struct drm_i915_private *i915 = migrate->context->engine->i915;
551e288e178SMatthew Auld 	struct drm_i915_gem_object *obj;
552e288e178SMatthew Auld 	struct intel_context *ce;
553e288e178SMatthew Auld 	struct i915_request *rq, *prev;
554e288e178SMatthew Auld 	struct spinner_timer st;
555e288e178SMatthew Auld 	struct sgt_dma it;
556e288e178SMatthew Auld 	int len, sz, err;
557e288e178SMatthew Auld 	u32 *cs;
558e288e178SMatthew Auld 
559e288e178SMatthew Auld 	/*
560e288e178SMatthew Auld 	 * Simple regression test to check that we don't trample the
561e288e178SMatthew Auld 	 * rq->reserved_space when returning from emit_pte(), if the ring is
562e288e178SMatthew Auld 	 * nearly full.
563e288e178SMatthew Auld 	 */
564e288e178SMatthew Auld 
565e288e178SMatthew Auld 	if (igt_spinner_init(&st.spin, to_gt(i915)))
566e288e178SMatthew Auld 		return -ENOMEM;
567e288e178SMatthew Auld 
568e288e178SMatthew Auld 	obj = i915_gem_object_create_internal(i915, 2 * PAGE_SIZE);
569e288e178SMatthew Auld 	if (IS_ERR(obj)) {
570e288e178SMatthew Auld 		err = PTR_ERR(obj);
571e288e178SMatthew Auld 		goto out_spinner;
572e288e178SMatthew Auld 	}
573e288e178SMatthew Auld 
574e288e178SMatthew Auld 	err = i915_gem_object_pin_pages_unlocked(obj);
575e288e178SMatthew Auld 	if (err)
576e288e178SMatthew Auld 		goto out_obj;
577e288e178SMatthew Auld 
578e288e178SMatthew Auld 	ce = intel_migrate_create_context(migrate);
579e288e178SMatthew Auld 	if (IS_ERR(ce)) {
580e288e178SMatthew Auld 		err = PTR_ERR(ce);
581e288e178SMatthew Auld 		goto out_obj;
582e288e178SMatthew Auld 	}
583e288e178SMatthew Auld 
584e288e178SMatthew Auld 	ce->ring_size = SZ_4K; /* Not too big */
585e288e178SMatthew Auld 
586e288e178SMatthew Auld 	err = intel_context_pin(ce);
587e288e178SMatthew Auld 	if (err)
588e288e178SMatthew Auld 		goto out_put;
589e288e178SMatthew Auld 
590e288e178SMatthew Auld 	rq = igt_spinner_create_request(&st.spin, ce, MI_ARB_CHECK);
591e288e178SMatthew Auld 	if (IS_ERR(rq)) {
592e288e178SMatthew Auld 		err = PTR_ERR(rq);
593e288e178SMatthew Auld 		goto out_unpin;
594e288e178SMatthew Auld 	}
595e288e178SMatthew Auld 
596e288e178SMatthew Auld 	i915_request_add(rq);
597e288e178SMatthew Auld 	if (!igt_wait_for_spinner(&st.spin, rq)) {
598e288e178SMatthew Auld 		err = -EIO;
599e288e178SMatthew Auld 		goto out_unpin;
600e288e178SMatthew Auld 	}
601e288e178SMatthew Auld 
602e288e178SMatthew Auld 	/*
603e288e178SMatthew Auld 	 * Fill the rest of the ring leaving I915_EMIT_PTE_NUM_DWORDS +
604e288e178SMatthew Auld 	 * ring->reserved_space at the end. To actually emit the PTEs we require
605e288e178SMatthew Auld 	 * slightly more than I915_EMIT_PTE_NUM_DWORDS, since our object size is
606e288e178SMatthew Auld 	 * greater than PAGE_SIZE. The correct behaviour is to wait for more
607e288e178SMatthew Auld 	 * ring space in emit_pte(), otherwise we trample on the reserved_space
608e288e178SMatthew Auld 	 * resulting in crashes when later submitting the rq.
609e288e178SMatthew Auld 	 */
610e288e178SMatthew Auld 
611e288e178SMatthew Auld 	prev = NULL;
612e288e178SMatthew Auld 	do {
613e288e178SMatthew Auld 		if (prev)
614e288e178SMatthew Auld 			i915_request_add(rq);
615e288e178SMatthew Auld 
616e288e178SMatthew Auld 		rq = i915_request_create(ce);
617e288e178SMatthew Auld 		if (IS_ERR(rq)) {
618e288e178SMatthew Auld 			err = PTR_ERR(rq);
619e288e178SMatthew Auld 			goto out_unpin;
620e288e178SMatthew Auld 		}
621e288e178SMatthew Auld 
622e288e178SMatthew Auld 		sz = (rq->ring->space - rq->reserved_space) / sizeof(u32) -
623e288e178SMatthew Auld 			I915_EMIT_PTE_NUM_DWORDS;
624e288e178SMatthew Auld 		sz = min_t(u32, sz, (SZ_1K - rq->reserved_space) / sizeof(u32) -
625e288e178SMatthew Auld 			   I915_EMIT_PTE_NUM_DWORDS);
626e288e178SMatthew Auld 		cs = intel_ring_begin(rq, sz);
627e288e178SMatthew Auld 		if (IS_ERR(cs)) {
628e288e178SMatthew Auld 			err = PTR_ERR(cs);
629e288e178SMatthew Auld 			goto out_rq;
630e288e178SMatthew Auld 		}
631e288e178SMatthew Auld 
632e288e178SMatthew Auld 		memset32(cs, MI_NOOP, sz);
633e288e178SMatthew Auld 		cs += sz;
634e288e178SMatthew Auld 		intel_ring_advance(rq, cs);
635e288e178SMatthew Auld 
636e288e178SMatthew Auld 		pr_info("%s emit=%u sz=%d\n", __func__, rq->ring->emit, sz);
637e288e178SMatthew Auld 
638e288e178SMatthew Auld 		prev = rq;
639e288e178SMatthew Auld 	} while (rq->ring->space > (rq->reserved_space +
640e288e178SMatthew Auld 				    I915_EMIT_PTE_NUM_DWORDS * sizeof(u32)));
641e288e178SMatthew Auld 
642e288e178SMatthew Auld 	timer_setup_on_stack(&st.timer, spinner_kill, 0);
643e288e178SMatthew Auld 	mod_timer(&st.timer, jiffies + 2 * HZ);
644e288e178SMatthew Auld 
645e288e178SMatthew Auld 	/*
646e288e178SMatthew Auld 	 * This should wait for the spinner to be killed, otherwise we should go
647e288e178SMatthew Auld 	 * down in flames when doing i915_request_add().
648e288e178SMatthew Auld 	 */
649e288e178SMatthew Auld 	pr_info("%s emite_pte ring space=%u\n", __func__, rq->ring->space);
650e288e178SMatthew Auld 	it = sg_sgt(obj->mm.pages->sgl);
6519275277dSFei Yang 	len = emit_pte(rq, &it, obj->pat_index, false, 0, CHUNK_SZ);
652e288e178SMatthew Auld 	if (!len) {
653e288e178SMatthew Auld 		err = -EINVAL;
654e288e178SMatthew Auld 		goto out_rq;
655e288e178SMatthew Auld 	}
656e288e178SMatthew Auld 	if (len < 0) {
657e288e178SMatthew Auld 		err = len;
658e288e178SMatthew Auld 		goto out_rq;
659e288e178SMatthew Auld 	}
660e288e178SMatthew Auld 
661e288e178SMatthew Auld out_rq:
662e288e178SMatthew Auld 	i915_request_add(rq); /* GEM_BUG_ON(rq->reserved_space > ring->space)? */
663e288e178SMatthew Auld 	del_timer_sync(&st.timer);
664e288e178SMatthew Auld 	destroy_timer_on_stack(&st.timer);
665e288e178SMatthew Auld out_unpin:
666e288e178SMatthew Auld 	intel_context_unpin(ce);
667e288e178SMatthew Auld out_put:
668e288e178SMatthew Auld 	intel_context_put(ce);
669e288e178SMatthew Auld out_obj:
670e288e178SMatthew Auld 	i915_gem_object_put(obj);
671e288e178SMatthew Auld out_spinner:
672e288e178SMatthew Auld 	igt_spinner_fini(&st.spin);
673e288e178SMatthew Auld 	return err;
674e288e178SMatthew Auld }
675e288e178SMatthew Auld 
676cf586021SChris Wilson struct threaded_migrate {
677cf586021SChris Wilson 	struct intel_migrate *migrate;
678cf586021SChris Wilson 	struct task_struct *tsk;
679cf586021SChris Wilson 	struct rnd_state prng;
680cf586021SChris Wilson };
681cf586021SChris Wilson 
threaded_migrate(struct intel_migrate * migrate,int (* fn)(void * arg),unsigned int flags)682cf586021SChris Wilson static int threaded_migrate(struct intel_migrate *migrate,
683cf586021SChris Wilson 			    int (*fn)(void *arg),
684cf586021SChris Wilson 			    unsigned int flags)
685cf586021SChris Wilson {
686cf586021SChris Wilson 	const unsigned int n_cpus = num_online_cpus() + 1;
687cf586021SChris Wilson 	struct threaded_migrate *thread;
688cf586021SChris Wilson 	I915_RND_STATE(prng);
689cf586021SChris Wilson 	unsigned int i;
690cf586021SChris Wilson 	int err = 0;
691cf586021SChris Wilson 
692cf586021SChris Wilson 	thread = kcalloc(n_cpus, sizeof(*thread), GFP_KERNEL);
693cf586021SChris Wilson 	if (!thread)
694cf586021SChris Wilson 		return 0;
695cf586021SChris Wilson 
696cf586021SChris Wilson 	for (i = 0; i < n_cpus; ++i) {
697cf586021SChris Wilson 		struct task_struct *tsk;
698cf586021SChris Wilson 
699cf586021SChris Wilson 		thread[i].migrate = migrate;
700cf586021SChris Wilson 		thread[i].prng =
701cf586021SChris Wilson 			I915_RND_STATE_INITIALIZER(prandom_u32_state(&prng));
702cf586021SChris Wilson 
703cf586021SChris Wilson 		tsk = kthread_run(fn, &thread[i], "igt-%d", i);
704cf586021SChris Wilson 		if (IS_ERR(tsk)) {
705cf586021SChris Wilson 			err = PTR_ERR(tsk);
706cf586021SChris Wilson 			break;
707cf586021SChris Wilson 		}
708cf586021SChris Wilson 
709cf586021SChris Wilson 		get_task_struct(tsk);
710cf586021SChris Wilson 		thread[i].tsk = tsk;
711cf586021SChris Wilson 	}
712cf586021SChris Wilson 
713cf586021SChris Wilson 	msleep(10); /* start all threads before we kthread_stop() */
714cf586021SChris Wilson 
715cf586021SChris Wilson 	for (i = 0; i < n_cpus; ++i) {
716cf586021SChris Wilson 		struct task_struct *tsk = thread[i].tsk;
717cf586021SChris Wilson 		int status;
718cf586021SChris Wilson 
719cf586021SChris Wilson 		if (IS_ERR_OR_NULL(tsk))
720cf586021SChris Wilson 			continue;
721cf586021SChris Wilson 
722*a9da6ddaSAndreas Gruenbacher 		status = kthread_stop_put(tsk);
723cf586021SChris Wilson 		if (status && !err)
724cf586021SChris Wilson 			err = status;
725cf586021SChris Wilson 	}
726cf586021SChris Wilson 
727cf586021SChris Wilson 	kfree(thread);
728cf586021SChris Wilson 	return err;
729cf586021SChris Wilson }
730cf586021SChris Wilson 
__thread_migrate_copy(void * arg)731cf586021SChris Wilson static int __thread_migrate_copy(void *arg)
732cf586021SChris Wilson {
733cf586021SChris Wilson 	struct threaded_migrate *tm = arg;
734cf586021SChris Wilson 
735cf586021SChris Wilson 	return migrate_copy(tm->migrate, 2 * CHUNK_SZ, &tm->prng);
736cf586021SChris Wilson }
737cf586021SChris Wilson 
thread_migrate_copy(void * arg)738cf586021SChris Wilson static int thread_migrate_copy(void *arg)
739cf586021SChris Wilson {
740f7f0ca57SMatthew Auld 	struct intel_gt *gt = arg;
741f7f0ca57SMatthew Auld 	struct intel_migrate *migrate = &gt->migrate;
742f7f0ca57SMatthew Auld 
743f7f0ca57SMatthew Auld 	return threaded_migrate(migrate, __thread_migrate_copy, 0);
744cf586021SChris Wilson }
745cf586021SChris Wilson 
__thread_global_copy(void * arg)746cf586021SChris Wilson static int __thread_global_copy(void *arg)
747cf586021SChris Wilson {
748cf586021SChris Wilson 	struct threaded_migrate *tm = arg;
749cf586021SChris Wilson 
750cf586021SChris Wilson 	return global_copy(tm->migrate, 2 * CHUNK_SZ, &tm->prng);
751cf586021SChris Wilson }
752cf586021SChris Wilson 
thread_global_copy(void * arg)753cf586021SChris Wilson static int thread_global_copy(void *arg)
754cf586021SChris Wilson {
755f7f0ca57SMatthew Auld 	struct intel_gt *gt = arg;
756f7f0ca57SMatthew Auld 	struct intel_migrate *migrate = &gt->migrate;
757f7f0ca57SMatthew Auld 
758f7f0ca57SMatthew Auld 	return threaded_migrate(migrate, __thread_global_copy, 0);
759cf586021SChris Wilson }
760cf586021SChris Wilson 
__thread_migrate_clear(void * arg)761563baae1SChris Wilson static int __thread_migrate_clear(void *arg)
762563baae1SChris Wilson {
763563baae1SChris Wilson 	struct threaded_migrate *tm = arg;
764563baae1SChris Wilson 
765563baae1SChris Wilson 	return migrate_clear(tm->migrate, 2 * CHUNK_SZ, &tm->prng);
766563baae1SChris Wilson }
767563baae1SChris Wilson 
__thread_global_clear(void * arg)768563baae1SChris Wilson static int __thread_global_clear(void *arg)
769563baae1SChris Wilson {
770563baae1SChris Wilson 	struct threaded_migrate *tm = arg;
771563baae1SChris Wilson 
772563baae1SChris Wilson 	return global_clear(tm->migrate, 2 * CHUNK_SZ, &tm->prng);
773563baae1SChris Wilson }
774563baae1SChris Wilson 
thread_migrate_clear(void * arg)775563baae1SChris Wilson static int thread_migrate_clear(void *arg)
776563baae1SChris Wilson {
777f7f0ca57SMatthew Auld 	struct intel_gt *gt = arg;
778f7f0ca57SMatthew Auld 	struct intel_migrate *migrate = &gt->migrate;
779f7f0ca57SMatthew Auld 
780f7f0ca57SMatthew Auld 	return threaded_migrate(migrate, __thread_migrate_clear, 0);
781563baae1SChris Wilson }
782563baae1SChris Wilson 
thread_global_clear(void * arg)783563baae1SChris Wilson static int thread_global_clear(void *arg)
784563baae1SChris Wilson {
785f7f0ca57SMatthew Auld 	struct intel_gt *gt = arg;
786f7f0ca57SMatthew Auld 	struct intel_migrate *migrate = &gt->migrate;
787f7f0ca57SMatthew Auld 
788f7f0ca57SMatthew Auld 	return threaded_migrate(migrate, __thread_global_clear, 0);
789563baae1SChris Wilson }
790563baae1SChris Wilson 
intel_migrate_live_selftests(struct drm_i915_private * i915)791cf586021SChris Wilson int intel_migrate_live_selftests(struct drm_i915_private *i915)
792cf586021SChris Wilson {
793cf586021SChris Wilson 	static const struct i915_subtest tests[] = {
794cf586021SChris Wilson 		SUBTEST(live_migrate_copy),
795563baae1SChris Wilson 		SUBTEST(live_migrate_clear),
796e288e178SMatthew Auld 		SUBTEST(live_emit_pte_full_ring),
797cf586021SChris Wilson 		SUBTEST(thread_migrate_copy),
798563baae1SChris Wilson 		SUBTEST(thread_migrate_clear),
799cf586021SChris Wilson 		SUBTEST(thread_global_copy),
800563baae1SChris Wilson 		SUBTEST(thread_global_clear),
801cf586021SChris Wilson 	};
802c14adcbdSMichał Winiarski 	struct intel_gt *gt = to_gt(i915);
803cf586021SChris Wilson 
80494ce0d65SChris Wilson 	if (!gt->migrate.context)
805cf586021SChris Wilson 		return 0;
806cf586021SChris Wilson 
807f7f0ca57SMatthew Auld 	return intel_gt_live_subtests(tests, gt);
80894ce0d65SChris Wilson }
809cf586021SChris Wilson 
81094ce0d65SChris Wilson static struct drm_i915_gem_object *
create_init_lmem_internal(struct intel_gt * gt,size_t sz,bool try_lmem)81194ce0d65SChris Wilson create_init_lmem_internal(struct intel_gt *gt, size_t sz, bool try_lmem)
81294ce0d65SChris Wilson {
81394ce0d65SChris Wilson 	struct drm_i915_gem_object *obj = NULL;
81494ce0d65SChris Wilson 	int err;
81594ce0d65SChris Wilson 
81694ce0d65SChris Wilson 	if (try_lmem)
81794ce0d65SChris Wilson 		obj = i915_gem_object_create_lmem(gt->i915, sz, 0);
81894ce0d65SChris Wilson 
81994ce0d65SChris Wilson 	if (IS_ERR_OR_NULL(obj)) {
82094ce0d65SChris Wilson 		obj = i915_gem_object_create_internal(gt->i915, sz);
82194ce0d65SChris Wilson 		if (IS_ERR(obj))
82294ce0d65SChris Wilson 			return obj;
82394ce0d65SChris Wilson 	}
82494ce0d65SChris Wilson 
825d8be1357SMaarten Lankhorst 	i915_gem_object_trylock(obj, NULL);
82694ce0d65SChris Wilson 	err = i915_gem_object_pin_pages(obj);
82794ce0d65SChris Wilson 	if (err) {
82894ce0d65SChris Wilson 		i915_gem_object_unlock(obj);
82994ce0d65SChris Wilson 		i915_gem_object_put(obj);
83094ce0d65SChris Wilson 		return ERR_PTR(err);
83194ce0d65SChris Wilson 	}
83294ce0d65SChris Wilson 
83394ce0d65SChris Wilson 	return obj;
83494ce0d65SChris Wilson }
83594ce0d65SChris Wilson 
wrap_ktime_compare(const void * A,const void * B)83694ce0d65SChris Wilson static int wrap_ktime_compare(const void *A, const void *B)
83794ce0d65SChris Wilson {
83894ce0d65SChris Wilson 	const ktime_t *a = A, *b = B;
83994ce0d65SChris Wilson 
84094ce0d65SChris Wilson 	return ktime_compare(*a, *b);
84194ce0d65SChris Wilson }
84294ce0d65SChris Wilson 
__perf_clear_blt(struct intel_context * ce,struct scatterlist * sg,unsigned int pat_index,bool is_lmem,size_t sz)84394ce0d65SChris Wilson static int __perf_clear_blt(struct intel_context *ce,
84494ce0d65SChris Wilson 			    struct scatterlist *sg,
8459275277dSFei Yang 			    unsigned int pat_index,
84694ce0d65SChris Wilson 			    bool is_lmem,
84794ce0d65SChris Wilson 			    size_t sz)
84894ce0d65SChris Wilson {
84994ce0d65SChris Wilson 	ktime_t t[5];
85094ce0d65SChris Wilson 	int pass;
85194ce0d65SChris Wilson 	int err = 0;
85294ce0d65SChris Wilson 
85394ce0d65SChris Wilson 	for (pass = 0; pass < ARRAY_SIZE(t); pass++) {
85494ce0d65SChris Wilson 		struct i915_request *rq;
85594ce0d65SChris Wilson 		ktime_t t0, t1;
85694ce0d65SChris Wilson 
85794ce0d65SChris Wilson 		t0 = ktime_get();
85894ce0d65SChris Wilson 
8599275277dSFei Yang 		err = intel_context_migrate_clear(ce, NULL, sg, pat_index,
86094ce0d65SChris Wilson 						  is_lmem, 0, &rq);
86194ce0d65SChris Wilson 		if (rq) {
86294ce0d65SChris Wilson 			if (i915_request_wait(rq, 0, MAX_SCHEDULE_TIMEOUT) < 0)
86394ce0d65SChris Wilson 				err = -EIO;
86494ce0d65SChris Wilson 			i915_request_put(rq);
86594ce0d65SChris Wilson 		}
86694ce0d65SChris Wilson 		if (err)
86794ce0d65SChris Wilson 			break;
86894ce0d65SChris Wilson 
86994ce0d65SChris Wilson 		t1 = ktime_get();
87094ce0d65SChris Wilson 		t[pass] = ktime_sub(t1, t0);
87194ce0d65SChris Wilson 	}
87294ce0d65SChris Wilson 	if (err)
873cf586021SChris Wilson 		return err;
87494ce0d65SChris Wilson 
87594ce0d65SChris Wilson 	sort(t, ARRAY_SIZE(t), sizeof(*t), wrap_ktime_compare, NULL);
87694ce0d65SChris Wilson 	pr_info("%s: %zd KiB fill: %lld MiB/s\n",
87794ce0d65SChris Wilson 		ce->engine->name, sz >> 10,
87894ce0d65SChris Wilson 		div64_u64(mul_u32_u32(4 * sz,
87994ce0d65SChris Wilson 				      1000 * 1000 * 1000),
88094ce0d65SChris Wilson 			  t[1] + 2 * t[2] + t[3]) >> 20);
88194ce0d65SChris Wilson 	return 0;
88294ce0d65SChris Wilson }
88394ce0d65SChris Wilson 
perf_clear_blt(void * arg)88494ce0d65SChris Wilson static int perf_clear_blt(void *arg)
88594ce0d65SChris Wilson {
88694ce0d65SChris Wilson 	struct intel_gt *gt = arg;
88794ce0d65SChris Wilson 	static const unsigned long sizes[] = {
88894ce0d65SChris Wilson 		SZ_4K,
88994ce0d65SChris Wilson 		SZ_64K,
89094ce0d65SChris Wilson 		SZ_2M,
89194ce0d65SChris Wilson 		SZ_64M
89294ce0d65SChris Wilson 	};
89394ce0d65SChris Wilson 	int i;
89494ce0d65SChris Wilson 
89594ce0d65SChris Wilson 	for (i = 0; i < ARRAY_SIZE(sizes); i++) {
89694ce0d65SChris Wilson 		struct drm_i915_gem_object *dst;
89794ce0d65SChris Wilson 		int err;
89894ce0d65SChris Wilson 
89994ce0d65SChris Wilson 		dst = create_init_lmem_internal(gt, sizes[i], true);
90094ce0d65SChris Wilson 		if (IS_ERR(dst))
90194ce0d65SChris Wilson 			return PTR_ERR(dst);
90294ce0d65SChris Wilson 
90394ce0d65SChris Wilson 		err = __perf_clear_blt(gt->migrate.context,
90494ce0d65SChris Wilson 				       dst->mm.pages->sgl,
9059275277dSFei Yang 				       i915_gem_get_pat_index(gt->i915,
9069275277dSFei Yang 							      I915_CACHE_NONE),
90794ce0d65SChris Wilson 				       i915_gem_object_is_lmem(dst),
90894ce0d65SChris Wilson 				       sizes[i]);
90994ce0d65SChris Wilson 
91094ce0d65SChris Wilson 		i915_gem_object_unlock(dst);
91194ce0d65SChris Wilson 		i915_gem_object_put(dst);
91294ce0d65SChris Wilson 		if (err)
91394ce0d65SChris Wilson 			return err;
91494ce0d65SChris Wilson 	}
91594ce0d65SChris Wilson 
91694ce0d65SChris Wilson 	return 0;
91794ce0d65SChris Wilson }
91894ce0d65SChris Wilson 
__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)91994ce0d65SChris Wilson static int __perf_copy_blt(struct intel_context *ce,
92094ce0d65SChris Wilson 			   struct scatterlist *src,
9219275277dSFei Yang 			   unsigned int src_pat_index,
92294ce0d65SChris Wilson 			   bool src_is_lmem,
92394ce0d65SChris Wilson 			   struct scatterlist *dst,
9249275277dSFei Yang 			   unsigned int dst_pat_index,
92594ce0d65SChris Wilson 			   bool dst_is_lmem,
92694ce0d65SChris Wilson 			   size_t sz)
92794ce0d65SChris Wilson {
92894ce0d65SChris Wilson 	ktime_t t[5];
92994ce0d65SChris Wilson 	int pass;
93094ce0d65SChris Wilson 	int err = 0;
93194ce0d65SChris Wilson 
93294ce0d65SChris Wilson 	for (pass = 0; pass < ARRAY_SIZE(t); pass++) {
93394ce0d65SChris Wilson 		struct i915_request *rq;
93494ce0d65SChris Wilson 		ktime_t t0, t1;
93594ce0d65SChris Wilson 
93694ce0d65SChris Wilson 		t0 = ktime_get();
93794ce0d65SChris Wilson 
93894ce0d65SChris Wilson 		err = intel_context_migrate_copy(ce, NULL,
9399275277dSFei Yang 						 src, src_pat_index,
94094ce0d65SChris Wilson 						 src_is_lmem,
9419275277dSFei Yang 						 dst, dst_pat_index,
94294ce0d65SChris Wilson 						 dst_is_lmem,
94394ce0d65SChris Wilson 						 &rq);
94494ce0d65SChris Wilson 		if (rq) {
94594ce0d65SChris Wilson 			if (i915_request_wait(rq, 0, MAX_SCHEDULE_TIMEOUT) < 0)
94694ce0d65SChris Wilson 				err = -EIO;
94794ce0d65SChris Wilson 			i915_request_put(rq);
94894ce0d65SChris Wilson 		}
94994ce0d65SChris Wilson 		if (err)
95094ce0d65SChris Wilson 			break;
95194ce0d65SChris Wilson 
95294ce0d65SChris Wilson 		t1 = ktime_get();
95394ce0d65SChris Wilson 		t[pass] = ktime_sub(t1, t0);
95494ce0d65SChris Wilson 	}
95594ce0d65SChris Wilson 	if (err)
95694ce0d65SChris Wilson 		return err;
95794ce0d65SChris Wilson 
95894ce0d65SChris Wilson 	sort(t, ARRAY_SIZE(t), sizeof(*t), wrap_ktime_compare, NULL);
95994ce0d65SChris Wilson 	pr_info("%s: %zd KiB copy: %lld MiB/s\n",
96094ce0d65SChris Wilson 		ce->engine->name, sz >> 10,
96194ce0d65SChris Wilson 		div64_u64(mul_u32_u32(4 * sz,
96294ce0d65SChris Wilson 				      1000 * 1000 * 1000),
96394ce0d65SChris Wilson 			  t[1] + 2 * t[2] + t[3]) >> 20);
96494ce0d65SChris Wilson 	return 0;
96594ce0d65SChris Wilson }
96694ce0d65SChris Wilson 
perf_copy_blt(void * arg)96794ce0d65SChris Wilson static int perf_copy_blt(void *arg)
96894ce0d65SChris Wilson {
96994ce0d65SChris Wilson 	struct intel_gt *gt = arg;
97094ce0d65SChris Wilson 	static const unsigned long sizes[] = {
97194ce0d65SChris Wilson 		SZ_4K,
97294ce0d65SChris Wilson 		SZ_64K,
97394ce0d65SChris Wilson 		SZ_2M,
97494ce0d65SChris Wilson 		SZ_64M
97594ce0d65SChris Wilson 	};
97694ce0d65SChris Wilson 	int i;
97794ce0d65SChris Wilson 
97894ce0d65SChris Wilson 	for (i = 0; i < ARRAY_SIZE(sizes); i++) {
97994ce0d65SChris Wilson 		struct drm_i915_gem_object *src, *dst;
980ae686e22SMatthew Auld 		size_t sz;
98194ce0d65SChris Wilson 		int err;
98294ce0d65SChris Wilson 
98394ce0d65SChris Wilson 		src = create_init_lmem_internal(gt, sizes[i], true);
98494ce0d65SChris Wilson 		if (IS_ERR(src))
98594ce0d65SChris Wilson 			return PTR_ERR(src);
98694ce0d65SChris Wilson 
987ae686e22SMatthew Auld 		sz = src->base.size;
988ae686e22SMatthew Auld 		dst = create_init_lmem_internal(gt, sz, false);
98994ce0d65SChris Wilson 		if (IS_ERR(dst)) {
99094ce0d65SChris Wilson 			err = PTR_ERR(dst);
99194ce0d65SChris Wilson 			goto err_src;
99294ce0d65SChris Wilson 		}
99394ce0d65SChris Wilson 
99494ce0d65SChris Wilson 		err = __perf_copy_blt(gt->migrate.context,
99594ce0d65SChris Wilson 				      src->mm.pages->sgl,
9969275277dSFei Yang 				      i915_gem_get_pat_index(gt->i915,
9979275277dSFei Yang 							     I915_CACHE_NONE),
99894ce0d65SChris Wilson 				      i915_gem_object_is_lmem(src),
99994ce0d65SChris Wilson 				      dst->mm.pages->sgl,
10009275277dSFei Yang 				      i915_gem_get_pat_index(gt->i915,
10019275277dSFei Yang 							     I915_CACHE_NONE),
100294ce0d65SChris Wilson 				      i915_gem_object_is_lmem(dst),
1003ae686e22SMatthew Auld 				      sz);
100494ce0d65SChris Wilson 
100594ce0d65SChris Wilson 		i915_gem_object_unlock(dst);
100694ce0d65SChris Wilson 		i915_gem_object_put(dst);
100794ce0d65SChris Wilson err_src:
100894ce0d65SChris Wilson 		i915_gem_object_unlock(src);
100994ce0d65SChris Wilson 		i915_gem_object_put(src);
101094ce0d65SChris Wilson 		if (err)
101194ce0d65SChris Wilson 			return err;
101294ce0d65SChris Wilson 	}
101394ce0d65SChris Wilson 
101494ce0d65SChris Wilson 	return 0;
101594ce0d65SChris Wilson }
101694ce0d65SChris Wilson 
intel_migrate_perf_selftests(struct drm_i915_private * i915)101794ce0d65SChris Wilson int intel_migrate_perf_selftests(struct drm_i915_private *i915)
101894ce0d65SChris Wilson {
101994ce0d65SChris Wilson 	static const struct i915_subtest tests[] = {
102094ce0d65SChris Wilson 		SUBTEST(perf_clear_blt),
102194ce0d65SChris Wilson 		SUBTEST(perf_copy_blt),
102294ce0d65SChris Wilson 	};
1023c14adcbdSMichał Winiarski 	struct intel_gt *gt = to_gt(i915);
102494ce0d65SChris Wilson 
102594ce0d65SChris Wilson 	if (intel_gt_is_wedged(gt))
102694ce0d65SChris Wilson 		return 0;
102794ce0d65SChris Wilson 
102894ce0d65SChris Wilson 	if (!gt->migrate.context)
102994ce0d65SChris Wilson 		return 0;
103094ce0d65SChris Wilson 
103194ce0d65SChris Wilson 	return intel_gt_live_subtests(tests, gt);
1032cf586021SChris Wilson }
1033