xref: /linux/drivers/gpu/drm/i915/selftests/intel_memory_region.c (revision ec8a42e7343234802b9054874fe01810880289ce)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2019 Intel Corporation
4  */
5 
6 #include <linux/prime_numbers.h>
7 #include <linux/sort.h>
8 
9 #include "../i915_selftest.h"
10 
11 #include "mock_drm.h"
12 #include "mock_gem_device.h"
13 #include "mock_region.h"
14 
15 #include "gem/i915_gem_context.h"
16 #include "gem/i915_gem_lmem.h"
17 #include "gem/i915_gem_region.h"
18 #include "gem/i915_gem_object_blt.h"
19 #include "gem/selftests/igt_gem_utils.h"
20 #include "gem/selftests/mock_context.h"
21 #include "gt/intel_engine_user.h"
22 #include "gt/intel_gt.h"
23 #include "i915_memcpy.h"
24 #include "selftests/igt_flush_test.h"
25 #include "selftests/i915_random.h"
26 
27 static void close_objects(struct intel_memory_region *mem,
28 			  struct list_head *objects)
29 {
30 	struct drm_i915_private *i915 = mem->i915;
31 	struct drm_i915_gem_object *obj, *on;
32 
33 	list_for_each_entry_safe(obj, on, objects, st_link) {
34 		if (i915_gem_object_has_pinned_pages(obj))
35 			i915_gem_object_unpin_pages(obj);
36 		/* No polluting the memory region between tests */
37 		__i915_gem_object_put_pages(obj);
38 		list_del(&obj->st_link);
39 		i915_gem_object_put(obj);
40 	}
41 
42 	cond_resched();
43 
44 	i915_gem_drain_freed_objects(i915);
45 }
46 
47 static int igt_mock_fill(void *arg)
48 {
49 	struct intel_memory_region *mem = arg;
50 	resource_size_t total = resource_size(&mem->region);
51 	resource_size_t page_size;
52 	resource_size_t rem;
53 	unsigned long max_pages;
54 	unsigned long page_num;
55 	LIST_HEAD(objects);
56 	int err = 0;
57 
58 	page_size = mem->mm.chunk_size;
59 	max_pages = div64_u64(total, page_size);
60 	rem = total;
61 
62 	for_each_prime_number_from(page_num, 1, max_pages) {
63 		resource_size_t size = page_num * page_size;
64 		struct drm_i915_gem_object *obj;
65 
66 		obj = i915_gem_object_create_region(mem, size, 0);
67 		if (IS_ERR(obj)) {
68 			err = PTR_ERR(obj);
69 			break;
70 		}
71 
72 		err = i915_gem_object_pin_pages(obj);
73 		if (err) {
74 			i915_gem_object_put(obj);
75 			break;
76 		}
77 
78 		list_add(&obj->st_link, &objects);
79 		rem -= size;
80 	}
81 
82 	if (err == -ENOMEM)
83 		err = 0;
84 	if (err == -ENXIO) {
85 		if (page_num * page_size <= rem) {
86 			pr_err("%s failed, space still left in region\n",
87 			       __func__);
88 			err = -EINVAL;
89 		} else {
90 			err = 0;
91 		}
92 	}
93 
94 	close_objects(mem, &objects);
95 
96 	return err;
97 }
98 
99 static struct drm_i915_gem_object *
100 igt_object_create(struct intel_memory_region *mem,
101 		  struct list_head *objects,
102 		  u64 size,
103 		  unsigned int flags)
104 {
105 	struct drm_i915_gem_object *obj;
106 	int err;
107 
108 	obj = i915_gem_object_create_region(mem, size, flags);
109 	if (IS_ERR(obj))
110 		return obj;
111 
112 	err = i915_gem_object_pin_pages(obj);
113 	if (err)
114 		goto put;
115 
116 	list_add(&obj->st_link, objects);
117 	return obj;
118 
119 put:
120 	i915_gem_object_put(obj);
121 	return ERR_PTR(err);
122 }
123 
124 static void igt_object_release(struct drm_i915_gem_object *obj)
125 {
126 	i915_gem_object_unpin_pages(obj);
127 	__i915_gem_object_put_pages(obj);
128 	list_del(&obj->st_link);
129 	i915_gem_object_put(obj);
130 }
131 
132 static int igt_mock_contiguous(void *arg)
133 {
134 	struct intel_memory_region *mem = arg;
135 	struct drm_i915_gem_object *obj;
136 	unsigned long n_objects;
137 	LIST_HEAD(objects);
138 	LIST_HEAD(holes);
139 	I915_RND_STATE(prng);
140 	resource_size_t total;
141 	resource_size_t min;
142 	u64 target;
143 	int err = 0;
144 
145 	total = resource_size(&mem->region);
146 
147 	/* Min size */
148 	obj = igt_object_create(mem, &objects, mem->mm.chunk_size,
149 				I915_BO_ALLOC_CONTIGUOUS);
150 	if (IS_ERR(obj))
151 		return PTR_ERR(obj);
152 
153 	if (obj->mm.pages->nents != 1) {
154 		pr_err("%s min object spans multiple sg entries\n", __func__);
155 		err = -EINVAL;
156 		goto err_close_objects;
157 	}
158 
159 	igt_object_release(obj);
160 
161 	/* Max size */
162 	obj = igt_object_create(mem, &objects, total, I915_BO_ALLOC_CONTIGUOUS);
163 	if (IS_ERR(obj))
164 		return PTR_ERR(obj);
165 
166 	if (obj->mm.pages->nents != 1) {
167 		pr_err("%s max object spans multiple sg entries\n", __func__);
168 		err = -EINVAL;
169 		goto err_close_objects;
170 	}
171 
172 	igt_object_release(obj);
173 
174 	/* Internal fragmentation should not bleed into the object size */
175 	target = i915_prandom_u64_state(&prng);
176 	div64_u64_rem(target, total, &target);
177 	target = round_up(target, PAGE_SIZE);
178 	target = max_t(u64, PAGE_SIZE, target);
179 
180 	obj = igt_object_create(mem, &objects, target,
181 				I915_BO_ALLOC_CONTIGUOUS);
182 	if (IS_ERR(obj))
183 		return PTR_ERR(obj);
184 
185 	if (obj->base.size != target) {
186 		pr_err("%s obj->base.size(%zx) != target(%llx)\n", __func__,
187 		       obj->base.size, target);
188 		err = -EINVAL;
189 		goto err_close_objects;
190 	}
191 
192 	if (obj->mm.pages->nents != 1) {
193 		pr_err("%s object spans multiple sg entries\n", __func__);
194 		err = -EINVAL;
195 		goto err_close_objects;
196 	}
197 
198 	igt_object_release(obj);
199 
200 	/*
201 	 * Try to fragment the address space, such that half of it is free, but
202 	 * the max contiguous block size is SZ_64K.
203 	 */
204 
205 	target = SZ_64K;
206 	n_objects = div64_u64(total, target);
207 
208 	while (n_objects--) {
209 		struct list_head *list;
210 
211 		if (n_objects % 2)
212 			list = &holes;
213 		else
214 			list = &objects;
215 
216 		obj = igt_object_create(mem, list, target,
217 					I915_BO_ALLOC_CONTIGUOUS);
218 		if (IS_ERR(obj)) {
219 			err = PTR_ERR(obj);
220 			goto err_close_objects;
221 		}
222 	}
223 
224 	close_objects(mem, &holes);
225 
226 	min = target;
227 	target = total >> 1;
228 
229 	/* Make sure we can still allocate all the fragmented space */
230 	obj = igt_object_create(mem, &objects, target, 0);
231 	if (IS_ERR(obj)) {
232 		err = PTR_ERR(obj);
233 		goto err_close_objects;
234 	}
235 
236 	igt_object_release(obj);
237 
238 	/*
239 	 * Even though we have enough free space, we don't have a big enough
240 	 * contiguous block. Make sure that holds true.
241 	 */
242 
243 	do {
244 		bool should_fail = target > min;
245 
246 		obj = igt_object_create(mem, &objects, target,
247 					I915_BO_ALLOC_CONTIGUOUS);
248 		if (should_fail != IS_ERR(obj)) {
249 			pr_err("%s target allocation(%llx) mismatch\n",
250 			       __func__, target);
251 			err = -EINVAL;
252 			goto err_close_objects;
253 		}
254 
255 		target >>= 1;
256 	} while (target >= mem->mm.chunk_size);
257 
258 err_close_objects:
259 	list_splice_tail(&holes, &objects);
260 	close_objects(mem, &objects);
261 	return err;
262 }
263 
264 static int igt_mock_splintered_region(void *arg)
265 {
266 	struct intel_memory_region *mem = arg;
267 	struct drm_i915_private *i915 = mem->i915;
268 	struct drm_i915_gem_object *obj;
269 	unsigned int expected_order;
270 	LIST_HEAD(objects);
271 	u64 size;
272 	int err = 0;
273 
274 	/*
275 	 * Sanity check we can still allocate everything even if the
276 	 * mm.max_order != mm.size. i.e our starting address space size is not a
277 	 * power-of-two.
278 	 */
279 
280 	size = (SZ_4G - 1) & PAGE_MASK;
281 	mem = mock_region_create(i915, 0, size, PAGE_SIZE, 0);
282 	if (IS_ERR(mem))
283 		return PTR_ERR(mem);
284 
285 	if (mem->mm.size != size) {
286 		pr_err("%s size mismatch(%llu != %llu)\n",
287 		       __func__, mem->mm.size, size);
288 		err = -EINVAL;
289 		goto out_put;
290 	}
291 
292 	expected_order = get_order(rounddown_pow_of_two(size));
293 	if (mem->mm.max_order != expected_order) {
294 		pr_err("%s order mismatch(%u != %u)\n",
295 		       __func__, mem->mm.max_order, expected_order);
296 		err = -EINVAL;
297 		goto out_put;
298 	}
299 
300 	obj = igt_object_create(mem, &objects, size, 0);
301 	if (IS_ERR(obj)) {
302 		err = PTR_ERR(obj);
303 		goto out_close;
304 	}
305 
306 	close_objects(mem, &objects);
307 
308 	/*
309 	 * While we should be able allocate everything without any flag
310 	 * restrictions, if we consider I915_BO_ALLOC_CONTIGUOUS then we are
311 	 * actually limited to the largest power-of-two for the region size i.e
312 	 * max_order, due to the inner workings of the buddy allocator. So make
313 	 * sure that does indeed hold true.
314 	 */
315 
316 	obj = igt_object_create(mem, &objects, size, I915_BO_ALLOC_CONTIGUOUS);
317 	if (!IS_ERR(obj)) {
318 		pr_err("%s too large contiguous allocation was not rejected\n",
319 		       __func__);
320 		err = -EINVAL;
321 		goto out_close;
322 	}
323 
324 	obj = igt_object_create(mem, &objects, rounddown_pow_of_two(size),
325 				I915_BO_ALLOC_CONTIGUOUS);
326 	if (IS_ERR(obj)) {
327 		pr_err("%s largest possible contiguous allocation failed\n",
328 		       __func__);
329 		err = PTR_ERR(obj);
330 		goto out_close;
331 	}
332 
333 out_close:
334 	close_objects(mem, &objects);
335 out_put:
336 	intel_memory_region_put(mem);
337 	return err;
338 }
339 
340 static int igt_gpu_write_dw(struct intel_context *ce,
341 			    struct i915_vma *vma,
342 			    u32 dword,
343 			    u32 value)
344 {
345 	return igt_gpu_fill_dw(ce, vma, dword * sizeof(u32),
346 			       vma->size >> PAGE_SHIFT, value);
347 }
348 
349 static int igt_cpu_check(struct drm_i915_gem_object *obj, u32 dword, u32 val)
350 {
351 	unsigned long n = obj->base.size >> PAGE_SHIFT;
352 	u32 *ptr;
353 	int err;
354 
355 	err = i915_gem_object_wait(obj, 0, MAX_SCHEDULE_TIMEOUT);
356 	if (err)
357 		return err;
358 
359 	ptr = i915_gem_object_pin_map(obj, I915_MAP_WC);
360 	if (IS_ERR(ptr))
361 		return PTR_ERR(ptr);
362 
363 	ptr += dword;
364 	while (n--) {
365 		if (*ptr != val) {
366 			pr_err("base[%u]=%08x, val=%08x\n",
367 			       dword, *ptr, val);
368 			err = -EINVAL;
369 			break;
370 		}
371 
372 		ptr += PAGE_SIZE / sizeof(*ptr);
373 	}
374 
375 	i915_gem_object_unpin_map(obj);
376 	return err;
377 }
378 
379 static int igt_gpu_write(struct i915_gem_context *ctx,
380 			 struct drm_i915_gem_object *obj)
381 {
382 	struct i915_gem_engines *engines;
383 	struct i915_gem_engines_iter it;
384 	struct i915_address_space *vm;
385 	struct intel_context *ce;
386 	I915_RND_STATE(prng);
387 	IGT_TIMEOUT(end_time);
388 	unsigned int count;
389 	struct i915_vma *vma;
390 	int *order;
391 	int i, n;
392 	int err = 0;
393 
394 	GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
395 
396 	n = 0;
397 	count = 0;
398 	for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it) {
399 		count++;
400 		if (!intel_engine_can_store_dword(ce->engine))
401 			continue;
402 
403 		vm = ce->vm;
404 		n++;
405 	}
406 	i915_gem_context_unlock_engines(ctx);
407 	if (!n)
408 		return 0;
409 
410 	order = i915_random_order(count * count, &prng);
411 	if (!order)
412 		return -ENOMEM;
413 
414 	vma = i915_vma_instance(obj, vm, NULL);
415 	if (IS_ERR(vma)) {
416 		err = PTR_ERR(vma);
417 		goto out_free;
418 	}
419 
420 	err = i915_vma_pin(vma, 0, 0, PIN_USER);
421 	if (err)
422 		goto out_free;
423 
424 	i = 0;
425 	engines = i915_gem_context_lock_engines(ctx);
426 	do {
427 		u32 rng = prandom_u32_state(&prng);
428 		u32 dword = offset_in_page(rng) / 4;
429 
430 		ce = engines->engines[order[i] % engines->num_engines];
431 		i = (i + 1) % (count * count);
432 		if (!ce || !intel_engine_can_store_dword(ce->engine))
433 			continue;
434 
435 		err = igt_gpu_write_dw(ce, vma, dword, rng);
436 		if (err)
437 			break;
438 
439 		err = igt_cpu_check(obj, dword, rng);
440 		if (err)
441 			break;
442 	} while (!__igt_timeout(end_time, NULL));
443 	i915_gem_context_unlock_engines(ctx);
444 
445 out_free:
446 	kfree(order);
447 
448 	if (err == -ENOMEM)
449 		err = 0;
450 
451 	return err;
452 }
453 
454 static int igt_lmem_create(void *arg)
455 {
456 	struct drm_i915_private *i915 = arg;
457 	struct drm_i915_gem_object *obj;
458 	int err = 0;
459 
460 	obj = i915_gem_object_create_lmem(i915, PAGE_SIZE, 0);
461 	if (IS_ERR(obj))
462 		return PTR_ERR(obj);
463 
464 	err = i915_gem_object_pin_pages(obj);
465 	if (err)
466 		goto out_put;
467 
468 	i915_gem_object_unpin_pages(obj);
469 out_put:
470 	i915_gem_object_put(obj);
471 
472 	return err;
473 }
474 
475 static int igt_lmem_write_gpu(void *arg)
476 {
477 	struct drm_i915_private *i915 = arg;
478 	struct drm_i915_gem_object *obj;
479 	struct i915_gem_context *ctx;
480 	struct file *file;
481 	I915_RND_STATE(prng);
482 	u32 sz;
483 	int err;
484 
485 	file = mock_file(i915);
486 	if (IS_ERR(file))
487 		return PTR_ERR(file);
488 
489 	ctx = live_context(i915, file);
490 	if (IS_ERR(ctx)) {
491 		err = PTR_ERR(ctx);
492 		goto out_file;
493 	}
494 
495 	sz = round_up(prandom_u32_state(&prng) % SZ_32M, PAGE_SIZE);
496 
497 	obj = i915_gem_object_create_lmem(i915, sz, 0);
498 	if (IS_ERR(obj)) {
499 		err = PTR_ERR(obj);
500 		goto out_file;
501 	}
502 
503 	err = i915_gem_object_pin_pages(obj);
504 	if (err)
505 		goto out_put;
506 
507 	err = igt_gpu_write(ctx, obj);
508 	if (err)
509 		pr_err("igt_gpu_write failed(%d)\n", err);
510 
511 	i915_gem_object_unpin_pages(obj);
512 out_put:
513 	i915_gem_object_put(obj);
514 out_file:
515 	fput(file);
516 	return err;
517 }
518 
519 static struct intel_engine_cs *
520 random_engine_class(struct drm_i915_private *i915,
521 		    unsigned int class,
522 		    struct rnd_state *prng)
523 {
524 	struct intel_engine_cs *engine;
525 	unsigned int count;
526 
527 	count = 0;
528 	for (engine = intel_engine_lookup_user(i915, class, 0);
529 	     engine && engine->uabi_class == class;
530 	     engine = rb_entry_safe(rb_next(&engine->uabi_node),
531 				    typeof(*engine), uabi_node))
532 		count++;
533 
534 	count = i915_prandom_u32_max_state(count, prng);
535 	return intel_engine_lookup_user(i915, class, count);
536 }
537 
538 static int igt_lmem_write_cpu(void *arg)
539 {
540 	struct drm_i915_private *i915 = arg;
541 	struct drm_i915_gem_object *obj;
542 	I915_RND_STATE(prng);
543 	IGT_TIMEOUT(end_time);
544 	u32 bytes[] = {
545 		0, /* rng placeholder */
546 		sizeof(u32),
547 		sizeof(u64),
548 		64, /* cl */
549 		PAGE_SIZE,
550 		PAGE_SIZE - sizeof(u32),
551 		PAGE_SIZE - sizeof(u64),
552 		PAGE_SIZE - 64,
553 	};
554 	struct intel_engine_cs *engine;
555 	u32 *vaddr;
556 	u32 sz;
557 	u32 i;
558 	int *order;
559 	int count;
560 	int err;
561 
562 	engine = random_engine_class(i915, I915_ENGINE_CLASS_COPY, &prng);
563 	if (!engine)
564 		return 0;
565 
566 	pr_info("%s: using %s\n", __func__, engine->name);
567 
568 	sz = round_up(prandom_u32_state(&prng) % SZ_32M, PAGE_SIZE);
569 	sz = max_t(u32, 2 * PAGE_SIZE, sz);
570 
571 	obj = i915_gem_object_create_lmem(i915, sz, I915_BO_ALLOC_CONTIGUOUS);
572 	if (IS_ERR(obj))
573 		return PTR_ERR(obj);
574 
575 	vaddr = i915_gem_object_pin_map(obj, I915_MAP_WC);
576 	if (IS_ERR(vaddr)) {
577 		err = PTR_ERR(vaddr);
578 		goto out_put;
579 	}
580 
581 	/* Put the pages into a known state -- from the gpu for added fun */
582 	intel_engine_pm_get(engine);
583 	err = i915_gem_object_fill_blt(obj, engine->kernel_context, 0xdeadbeaf);
584 	intel_engine_pm_put(engine);
585 	if (err)
586 		goto out_unpin;
587 
588 	i915_gem_object_lock(obj, NULL);
589 	err = i915_gem_object_set_to_wc_domain(obj, true);
590 	i915_gem_object_unlock(obj);
591 	if (err)
592 		goto out_unpin;
593 
594 	count = ARRAY_SIZE(bytes);
595 	order = i915_random_order(count * count, &prng);
596 	if (!order) {
597 		err = -ENOMEM;
598 		goto out_unpin;
599 	}
600 
601 	/* A random multiple of u32, picked between [64, PAGE_SIZE - 64] */
602 	bytes[0] = igt_random_offset(&prng, 64, PAGE_SIZE - 64, 0, sizeof(u32));
603 	GEM_BUG_ON(!IS_ALIGNED(bytes[0], sizeof(u32)));
604 
605 	i = 0;
606 	do {
607 		u32 offset;
608 		u32 align;
609 		u32 dword;
610 		u32 size;
611 		u32 val;
612 
613 		size = bytes[order[i] % count];
614 		i = (i + 1) % (count * count);
615 
616 		align = bytes[order[i] % count];
617 		i = (i + 1) % (count * count);
618 
619 		align = max_t(u32, sizeof(u32), rounddown_pow_of_two(align));
620 
621 		offset = igt_random_offset(&prng, 0, obj->base.size,
622 					   size, align);
623 
624 		val = prandom_u32_state(&prng);
625 		memset32(vaddr + offset / sizeof(u32), val ^ 0xdeadbeaf,
626 			 size / sizeof(u32));
627 
628 		/*
629 		 * Sample random dw -- don't waste precious time reading every
630 		 * single dw.
631 		 */
632 		dword = igt_random_offset(&prng, offset,
633 					  offset + size,
634 					  sizeof(u32), sizeof(u32));
635 		dword /= sizeof(u32);
636 		if (vaddr[dword] != (val ^ 0xdeadbeaf)) {
637 			pr_err("%s vaddr[%u]=%u, val=%u, size=%u, align=%u, offset=%u\n",
638 			       __func__, dword, vaddr[dword], val ^ 0xdeadbeaf,
639 			       size, align, offset);
640 			err = -EINVAL;
641 			break;
642 		}
643 	} while (!__igt_timeout(end_time, NULL));
644 
645 out_unpin:
646 	i915_gem_object_unpin_map(obj);
647 out_put:
648 	i915_gem_object_put(obj);
649 
650 	return err;
651 }
652 
653 static const char *repr_type(u32 type)
654 {
655 	switch (type) {
656 	case I915_MAP_WB:
657 		return "WB";
658 	case I915_MAP_WC:
659 		return "WC";
660 	}
661 
662 	return "";
663 }
664 
665 static struct drm_i915_gem_object *
666 create_region_for_mapping(struct intel_memory_region *mr, u64 size, u32 type,
667 			  void **out_addr)
668 {
669 	struct drm_i915_gem_object *obj;
670 	void *addr;
671 
672 	obj = i915_gem_object_create_region(mr, size, 0);
673 	if (IS_ERR(obj)) {
674 		if (PTR_ERR(obj) == -ENOSPC) /* Stolen memory */
675 			return ERR_PTR(-ENODEV);
676 		return obj;
677 	}
678 
679 	addr = i915_gem_object_pin_map(obj, type);
680 	if (IS_ERR(addr)) {
681 		i915_gem_object_put(obj);
682 		if (PTR_ERR(addr) == -ENXIO)
683 			return ERR_PTR(-ENODEV);
684 		return addr;
685 	}
686 
687 	*out_addr = addr;
688 	return obj;
689 }
690 
691 static int wrap_ktime_compare(const void *A, const void *B)
692 {
693 	const ktime_t *a = A, *b = B;
694 
695 	return ktime_compare(*a, *b);
696 }
697 
698 static void igt_memcpy_long(void *dst, const void *src, size_t size)
699 {
700 	unsigned long *tmp = dst;
701 	const unsigned long *s = src;
702 
703 	size = size / sizeof(unsigned long);
704 	while (size--)
705 		*tmp++ = *s++;
706 }
707 
708 static inline void igt_memcpy(void *dst, const void *src, size_t size)
709 {
710 	memcpy(dst, src, size);
711 }
712 
713 static inline void igt_memcpy_from_wc(void *dst, const void *src, size_t size)
714 {
715 	i915_memcpy_from_wc(dst, src, size);
716 }
717 
718 static int _perf_memcpy(struct intel_memory_region *src_mr,
719 			struct intel_memory_region *dst_mr,
720 			u64 size, u32 src_type, u32 dst_type)
721 {
722 	struct drm_i915_private *i915 = src_mr->i915;
723 	const struct {
724 		const char *name;
725 		void (*copy)(void *dst, const void *src, size_t size);
726 		bool skip;
727 	} tests[] = {
728 		{
729 			"memcpy",
730 			igt_memcpy,
731 		},
732 		{
733 			"memcpy_long",
734 			igt_memcpy_long,
735 		},
736 		{
737 			"memcpy_from_wc",
738 			igt_memcpy_from_wc,
739 			!i915_has_memcpy_from_wc(),
740 		},
741 	};
742 	struct drm_i915_gem_object *src, *dst;
743 	void *src_addr, *dst_addr;
744 	int ret = 0;
745 	int i;
746 
747 	src = create_region_for_mapping(src_mr, size, src_type, &src_addr);
748 	if (IS_ERR(src)) {
749 		ret = PTR_ERR(src);
750 		goto out;
751 	}
752 
753 	dst = create_region_for_mapping(dst_mr, size, dst_type, &dst_addr);
754 	if (IS_ERR(dst)) {
755 		ret = PTR_ERR(dst);
756 		goto out_unpin_src;
757 	}
758 
759 	for (i = 0; i < ARRAY_SIZE(tests); ++i) {
760 		ktime_t t[5];
761 		int pass;
762 
763 		if (tests[i].skip)
764 			continue;
765 
766 		for (pass = 0; pass < ARRAY_SIZE(t); pass++) {
767 			ktime_t t0, t1;
768 
769 			t0 = ktime_get();
770 
771 			tests[i].copy(dst_addr, src_addr, size);
772 
773 			t1 = ktime_get();
774 			t[pass] = ktime_sub(t1, t0);
775 		}
776 
777 		sort(t, ARRAY_SIZE(t), sizeof(*t), wrap_ktime_compare, NULL);
778 		pr_info("%s src(%s, %s) -> dst(%s, %s) %14s %4llu KiB copy: %5lld MiB/s\n",
779 			__func__,
780 			src_mr->name,
781 			repr_type(src_type),
782 			dst_mr->name,
783 			repr_type(dst_type),
784 			tests[i].name,
785 			size >> 10,
786 			div64_u64(mul_u32_u32(4 * size,
787 					      1000 * 1000 * 1000),
788 				  t[1] + 2 * t[2] + t[3]) >> 20);
789 
790 		cond_resched();
791 	}
792 
793 	i915_gem_object_unpin_map(dst);
794 	i915_gem_object_put(dst);
795 out_unpin_src:
796 	i915_gem_object_unpin_map(src);
797 	i915_gem_object_put(src);
798 
799 	i915_gem_drain_freed_objects(i915);
800 out:
801 	if (ret == -ENODEV)
802 		ret = 0;
803 
804 	return ret;
805 }
806 
807 static int perf_memcpy(void *arg)
808 {
809 	struct drm_i915_private *i915 = arg;
810 	static const u32 types[] = {
811 		I915_MAP_WB,
812 		I915_MAP_WC,
813 	};
814 	static const u32 sizes[] = {
815 		SZ_4K,
816 		SZ_64K,
817 		SZ_4M,
818 	};
819 	struct intel_memory_region *src_mr, *dst_mr;
820 	int src_id, dst_id;
821 	int i, j, k;
822 	int ret;
823 
824 	for_each_memory_region(src_mr, i915, src_id) {
825 		for_each_memory_region(dst_mr, i915, dst_id) {
826 			for (i = 0; i < ARRAY_SIZE(sizes); ++i) {
827 				for (j = 0; j < ARRAY_SIZE(types); ++j) {
828 					for (k = 0; k < ARRAY_SIZE(types); ++k) {
829 						ret = _perf_memcpy(src_mr,
830 								   dst_mr,
831 								   sizes[i],
832 								   types[j],
833 								   types[k]);
834 						if (ret)
835 							return ret;
836 					}
837 				}
838 			}
839 		}
840 	}
841 
842 	return 0;
843 }
844 
845 int intel_memory_region_mock_selftests(void)
846 {
847 	static const struct i915_subtest tests[] = {
848 		SUBTEST(igt_mock_fill),
849 		SUBTEST(igt_mock_contiguous),
850 		SUBTEST(igt_mock_splintered_region),
851 	};
852 	struct intel_memory_region *mem;
853 	struct drm_i915_private *i915;
854 	int err;
855 
856 	i915 = mock_gem_device();
857 	if (!i915)
858 		return -ENOMEM;
859 
860 	mem = mock_region_create(i915, 0, SZ_2G, I915_GTT_PAGE_SIZE_4K, 0);
861 	if (IS_ERR(mem)) {
862 		pr_err("failed to create memory region\n");
863 		err = PTR_ERR(mem);
864 		goto out_unref;
865 	}
866 
867 	err = i915_subtests(tests, mem);
868 
869 	intel_memory_region_put(mem);
870 out_unref:
871 	mock_destroy_device(i915);
872 	return err;
873 }
874 
875 int intel_memory_region_live_selftests(struct drm_i915_private *i915)
876 {
877 	static const struct i915_subtest tests[] = {
878 		SUBTEST(igt_lmem_create),
879 		SUBTEST(igt_lmem_write_cpu),
880 		SUBTEST(igt_lmem_write_gpu),
881 	};
882 
883 	if (!HAS_LMEM(i915)) {
884 		pr_info("device lacks LMEM support, skipping\n");
885 		return 0;
886 	}
887 
888 	if (intel_gt_is_wedged(&i915->gt))
889 		return 0;
890 
891 	return i915_live_subtests(tests, i915);
892 }
893 
894 int intel_memory_region_perf_selftests(struct drm_i915_private *i915)
895 {
896 	static const struct i915_subtest tests[] = {
897 		SUBTEST(perf_memcpy),
898 	};
899 
900 	if (intel_gt_is_wedged(&i915->gt))
901 		return 0;
902 
903 	return i915_live_subtests(tests, i915);
904 }
905