1
2
3
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
27static 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 i915_gem_object_lock(obj, NULL);
35 if (i915_gem_object_has_pinned_pages(obj))
36 i915_gem_object_unpin_pages(obj);
37
38 __i915_gem_object_put_pages(obj);
39 i915_gem_object_unlock(obj);
40 list_del(&obj->st_link);
41 i915_gem_object_put(obj);
42 }
43
44 cond_resched();
45
46 i915_gem_drain_freed_objects(i915);
47}
48
49static int igt_mock_fill(void *arg)
50{
51 struct intel_memory_region *mem = arg;
52 resource_size_t total = resource_size(&mem->region);
53 resource_size_t page_size;
54 resource_size_t rem;
55 unsigned long max_pages;
56 unsigned long page_num;
57 LIST_HEAD(objects);
58 int err = 0;
59
60 page_size = mem->chunk_size;
61 rem = total;
62retry:
63 max_pages = div64_u64(rem, page_size);
64
65 for_each_prime_number_from(page_num, 1, max_pages) {
66 resource_size_t size = page_num * page_size;
67 struct drm_i915_gem_object *obj;
68
69 obj = i915_gem_object_create_region(mem, size, 0);
70 if (IS_ERR(obj)) {
71 err = PTR_ERR(obj);
72 break;
73 }
74
75 err = i915_gem_object_pin_pages_unlocked(obj);
76 if (err) {
77 i915_gem_object_put(obj);
78 break;
79 }
80
81 list_add(&obj->st_link, &objects);
82 rem -= size;
83 }
84
85 if (err == -ENOMEM)
86 err = 0;
87 if (err == -ENXIO) {
88 if (page_num * page_size <= rem) {
89 if (mem->is_range_manager && max_pages > 1) {
90 max_pages >>= 1;
91 goto retry;
92 }
93
94 pr_err("%s failed, space still left in region\n",
95 __func__);
96 err = -EINVAL;
97 } else {
98 err = 0;
99 }
100 }
101
102 close_objects(mem, &objects);
103
104 return err;
105}
106
107static struct drm_i915_gem_object *
108igt_object_create(struct intel_memory_region *mem,
109 struct list_head *objects,
110 u64 size,
111 unsigned int flags)
112{
113 struct drm_i915_gem_object *obj;
114 int err;
115
116 obj = i915_gem_object_create_region(mem, size, flags);
117 if (IS_ERR(obj))
118 return obj;
119
120 err = i915_gem_object_pin_pages_unlocked(obj);
121 if (err)
122 goto put;
123
124 list_add(&obj->st_link, objects);
125 return obj;
126
127put:
128 i915_gem_object_put(obj);
129 return ERR_PTR(err);
130}
131
132static void igt_object_release(struct drm_i915_gem_object *obj)
133{
134 i915_gem_object_lock(obj, NULL);
135 i915_gem_object_unpin_pages(obj);
136 __i915_gem_object_put_pages(obj);
137 i915_gem_object_unlock(obj);
138 list_del(&obj->st_link);
139 i915_gem_object_put(obj);
140}
141
142static bool is_contiguous(struct drm_i915_gem_object *obj)
143{
144 struct scatterlist *sg;
145 dma_addr_t addr = -1;
146
147 for (sg = obj->mm.pages->sgl; sg; sg = sg_next(sg)) {
148 if (addr != -1 && sg_dma_address(sg) != addr)
149 return false;
150
151 addr = sg_dma_address(sg) + sg_dma_len(sg);
152 }
153
154 return true;
155}
156
157static int igt_mock_reserve(void *arg)
158{
159 struct intel_memory_region *mem = arg;
160 resource_size_t avail = resource_size(&mem->region);
161 struct drm_i915_gem_object *obj;
162 const u32 chunk_size = SZ_32M;
163 u32 i, offset, count, *order;
164 u64 allocated, cur_avail;
165 I915_RND_STATE(prng);
166 LIST_HEAD(objects);
167 int err = 0;
168
169 if (!list_empty(&mem->reserved)) {
170 pr_err("%s region reserved list is not empty\n", __func__);
171 return -EINVAL;
172 }
173
174 count = avail / chunk_size;
175 order = i915_random_order(count, &prng);
176 if (!order)
177 return 0;
178
179
180 for (i = 0; i < count; ++i) {
181 u64 start = order[i] * chunk_size;
182 u64 size = i915_prandom_u32_max_state(chunk_size, &prng);
183
184
185 if (!size)
186 continue;
187
188 size = round_up(size, PAGE_SIZE);
189 offset = igt_random_offset(&prng, 0, chunk_size, size,
190 PAGE_SIZE);
191
192 err = intel_memory_region_reserve(mem, start + offset, size);
193 if (err) {
194 pr_err("%s failed to reserve range", __func__);
195 goto out_close;
196 }
197
198
199 avail -= size;
200 }
201
202
203 allocated = 0;
204 cur_avail = avail;
205 do {
206 u32 size = i915_prandom_u32_max_state(cur_avail, &prng);
207
208retry:
209 size = max_t(u32, round_up(size, PAGE_SIZE), PAGE_SIZE);
210 obj = igt_object_create(mem, &objects, size, 0);
211 if (IS_ERR(obj)) {
212 if (PTR_ERR(obj) == -ENXIO) {
213 if (mem->is_range_manager &&
214 size > mem->chunk_size) {
215 size >>= 1;
216 goto retry;
217 }
218 break;
219 }
220 err = PTR_ERR(obj);
221 goto out_close;
222 }
223 cur_avail -= size;
224 allocated += size;
225 } while (1);
226
227 if (allocated != avail) {
228 pr_err("%s mismatch between allocation and free space", __func__);
229 err = -EINVAL;
230 }
231
232out_close:
233 kfree(order);
234 close_objects(mem, &objects);
235 intel_memory_region_unreserve(mem);
236 return err;
237}
238
239static int igt_mock_contiguous(void *arg)
240{
241 struct intel_memory_region *mem = arg;
242 struct drm_i915_gem_object *obj;
243 unsigned long n_objects;
244 LIST_HEAD(objects);
245 LIST_HEAD(holes);
246 I915_RND_STATE(prng);
247 resource_size_t total;
248 resource_size_t min;
249 u64 target;
250 int err = 0;
251
252 total = resource_size(&mem->region);
253
254
255 obj = igt_object_create(mem, &objects, mem->chunk_size,
256 I915_BO_ALLOC_CONTIGUOUS);
257 if (IS_ERR(obj))
258 return PTR_ERR(obj);
259
260 if (!is_contiguous(obj)) {
261 pr_err("%s min object spans disjoint sg entries\n", __func__);
262 err = -EINVAL;
263 goto err_close_objects;
264 }
265
266 igt_object_release(obj);
267
268
269 obj = igt_object_create(mem, &objects, total, I915_BO_ALLOC_CONTIGUOUS);
270 if (IS_ERR(obj))
271 return PTR_ERR(obj);
272
273 if (!is_contiguous(obj)) {
274 pr_err("%s max object spans disjoint sg entries\n", __func__);
275 err = -EINVAL;
276 goto err_close_objects;
277 }
278
279 igt_object_release(obj);
280
281
282 target = i915_prandom_u64_state(&prng);
283 div64_u64_rem(target, total, &target);
284 target = round_up(target, PAGE_SIZE);
285 target = max_t(u64, PAGE_SIZE, target);
286
287 obj = igt_object_create(mem, &objects, target,
288 I915_BO_ALLOC_CONTIGUOUS);
289 if (IS_ERR(obj))
290 return PTR_ERR(obj);
291
292 if (obj->base.size != target) {
293 pr_err("%s obj->base.size(%zx) != target(%llx)\n", __func__,
294 obj->base.size, target);
295 err = -EINVAL;
296 goto err_close_objects;
297 }
298
299 if (!is_contiguous(obj)) {
300 pr_err("%s object spans disjoint sg entries\n", __func__);
301 err = -EINVAL;
302 goto err_close_objects;
303 }
304
305 igt_object_release(obj);
306
307
308
309
310
311
312 target = SZ_64K;
313 n_objects = div64_u64(total, target);
314
315 while (n_objects--) {
316 struct list_head *list;
317
318 if (n_objects % 2)
319 list = &holes;
320 else
321 list = &objects;
322
323 obj = igt_object_create(mem, list, target,
324 I915_BO_ALLOC_CONTIGUOUS);
325 if (IS_ERR(obj)) {
326 err = PTR_ERR(obj);
327 goto err_close_objects;
328 }
329 }
330
331 close_objects(mem, &holes);
332
333 min = target;
334 target = total >> 1;
335
336 if (!mem->is_range_manager) {
337
338 obj = igt_object_create(mem, &objects, target, 0);
339 if (IS_ERR(obj)) {
340 err = PTR_ERR(obj);
341 goto err_close_objects;
342 }
343
344 igt_object_release(obj);
345 }
346
347
348
349
350
351
352 do {
353 bool should_fail = target > min;
354
355 obj = igt_object_create(mem, &objects, target,
356 I915_BO_ALLOC_CONTIGUOUS);
357 if (should_fail != IS_ERR(obj)) {
358 pr_err("%s target allocation(%llx) mismatch\n",
359 __func__, target);
360 err = -EINVAL;
361 goto err_close_objects;
362 }
363
364 target >>= 1;
365 } while (target >= mem->chunk_size);
366
367err_close_objects:
368 list_splice_tail(&holes, &objects);
369 close_objects(mem, &objects);
370 return err;
371}
372
373static int igt_mock_splintered_region(void *arg)
374{
375 struct intel_memory_region *mem = arg;
376 struct drm_i915_private *i915 = mem->i915;
377 struct drm_i915_gem_object *obj;
378 unsigned int expected_order;
379 LIST_HEAD(objects);
380 u64 size;
381 int err = 0;
382
383
384
385
386
387
388
389 size = (SZ_4G - 1) & PAGE_MASK;
390 mem = mock_region_create(i915, 0, size, PAGE_SIZE, 0);
391 if (IS_ERR(mem))
392 return PTR_ERR(mem);
393
394 expected_order = get_order(rounddown_pow_of_two(size));
395 if (mem->max_order != expected_order) {
396 pr_err("%s order mismatch(%u != %u)\n",
397 __func__, mem->max_order, expected_order);
398 err = -EINVAL;
399 goto out_put;
400 }
401
402 obj = igt_object_create(mem, &objects, size, 0);
403 if (IS_ERR(obj)) {
404 err = PTR_ERR(obj);
405 goto out_close;
406 }
407
408 close_objects(mem, &objects);
409
410
411
412
413
414
415
416
417
418 if (!mem->is_range_manager) {
419 obj = igt_object_create(mem, &objects, size,
420 I915_BO_ALLOC_CONTIGUOUS);
421 if (!IS_ERR(obj)) {
422 pr_err("%s too large contiguous allocation was not rejected\n",
423 __func__);
424 err = -EINVAL;
425 goto out_close;
426 }
427 }
428
429 obj = igt_object_create(mem, &objects, rounddown_pow_of_two(size),
430 I915_BO_ALLOC_CONTIGUOUS);
431 if (IS_ERR(obj)) {
432 pr_err("%s largest possible contiguous allocation failed\n",
433 __func__);
434 err = PTR_ERR(obj);
435 goto out_close;
436 }
437
438out_close:
439 close_objects(mem, &objects);
440out_put:
441 intel_memory_region_put(mem);
442 return err;
443}
444
445static int igt_gpu_write_dw(struct intel_context *ce,
446 struct i915_vma *vma,
447 u32 dword,
448 u32 value)
449{
450 return igt_gpu_fill_dw(ce, vma, dword * sizeof(u32),
451 vma->size >> PAGE_SHIFT, value);
452}
453
454static int igt_cpu_check(struct drm_i915_gem_object *obj, u32 dword, u32 val)
455{
456 unsigned long n = obj->base.size >> PAGE_SHIFT;
457 u32 *ptr;
458 int err;
459
460 err = i915_gem_object_wait(obj, 0, MAX_SCHEDULE_TIMEOUT);
461 if (err)
462 return err;
463
464 ptr = i915_gem_object_pin_map(obj, I915_MAP_WC);
465 if (IS_ERR(ptr))
466 return PTR_ERR(ptr);
467
468 ptr += dword;
469 while (n--) {
470 if (*ptr != val) {
471 pr_err("base[%u]=%08x, val=%08x\n",
472 dword, *ptr, val);
473 err = -EINVAL;
474 break;
475 }
476
477 ptr += PAGE_SIZE / sizeof(*ptr);
478 }
479
480 i915_gem_object_unpin_map(obj);
481 return err;
482}
483
484static int igt_gpu_write(struct i915_gem_context *ctx,
485 struct drm_i915_gem_object *obj)
486{
487 struct i915_gem_engines *engines;
488 struct i915_gem_engines_iter it;
489 struct i915_address_space *vm;
490 struct intel_context *ce;
491 I915_RND_STATE(prng);
492 IGT_TIMEOUT(end_time);
493 unsigned int count;
494 struct i915_vma *vma;
495 int *order;
496 int i, n;
497 int err = 0;
498
499 GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
500
501 n = 0;
502 count = 0;
503 for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it) {
504 count++;
505 if (!intel_engine_can_store_dword(ce->engine))
506 continue;
507
508 vm = ce->vm;
509 n++;
510 }
511 i915_gem_context_unlock_engines(ctx);
512 if (!n)
513 return 0;
514
515 order = i915_random_order(count * count, &prng);
516 if (!order)
517 return -ENOMEM;
518
519 vma = i915_vma_instance(obj, vm, NULL);
520 if (IS_ERR(vma)) {
521 err = PTR_ERR(vma);
522 goto out_free;
523 }
524
525 err = i915_vma_pin(vma, 0, 0, PIN_USER);
526 if (err)
527 goto out_free;
528
529 i = 0;
530 engines = i915_gem_context_lock_engines(ctx);
531 do {
532 u32 rng = prandom_u32_state(&prng);
533 u32 dword = offset_in_page(rng) / 4;
534
535 ce = engines->engines[order[i] % engines->num_engines];
536 i = (i + 1) % (count * count);
537 if (!ce || !intel_engine_can_store_dword(ce->engine))
538 continue;
539
540 err = igt_gpu_write_dw(ce, vma, dword, rng);
541 if (err)
542 break;
543
544 i915_gem_object_lock(obj, NULL);
545 err = igt_cpu_check(obj, dword, rng);
546 i915_gem_object_unlock(obj);
547 if (err)
548 break;
549 } while (!__igt_timeout(end_time, NULL));
550 i915_gem_context_unlock_engines(ctx);
551
552out_free:
553 kfree(order);
554
555 if (err == -ENOMEM)
556 err = 0;
557
558 return err;
559}
560
561static int igt_lmem_create(void *arg)
562{
563 struct drm_i915_private *i915 = arg;
564 struct drm_i915_gem_object *obj;
565 int err = 0;
566
567 obj = i915_gem_object_create_lmem(i915, PAGE_SIZE, 0);
568 if (IS_ERR(obj))
569 return PTR_ERR(obj);
570
571 err = i915_gem_object_pin_pages_unlocked(obj);
572 if (err)
573 goto out_put;
574
575 i915_gem_object_unpin_pages(obj);
576out_put:
577 i915_gem_object_put(obj);
578
579 return err;
580}
581
582static int igt_lmem_create_cleared_cpu(void *arg)
583{
584 struct drm_i915_private *i915 = arg;
585 I915_RND_STATE(prng);
586 IGT_TIMEOUT(end_time);
587 u32 size, i;
588 int err;
589
590 i915_gem_drain_freed_objects(i915);
591
592 size = max_t(u32, PAGE_SIZE, i915_prandom_u32_max_state(SZ_32M, &prng));
593 size = round_up(size, PAGE_SIZE);
594 i = 0;
595
596 do {
597 struct drm_i915_gem_object *obj;
598 unsigned int flags;
599 u32 dword, val;
600 void *vaddr;
601
602
603
604
605
606
607
608
609
610 flags = I915_BO_ALLOC_CPU_CLEAR;
611 if (i & 1)
612 flags = 0;
613
614 obj = i915_gem_object_create_lmem(i915, size, flags);
615 if (IS_ERR(obj))
616 return PTR_ERR(obj);
617
618 i915_gem_object_lock(obj, NULL);
619 err = i915_gem_object_pin_pages(obj);
620 if (err)
621 goto out_put;
622
623 dword = i915_prandom_u32_max_state(PAGE_SIZE / sizeof(u32),
624 &prng);
625
626 if (flags & I915_BO_ALLOC_CPU_CLEAR) {
627 err = igt_cpu_check(obj, dword, 0);
628 if (err) {
629 pr_err("%s failed with size=%u, flags=%u\n",
630 __func__, size, flags);
631 goto out_unpin;
632 }
633 }
634
635 vaddr = i915_gem_object_pin_map(obj, I915_MAP_WC);
636 if (IS_ERR(vaddr)) {
637 err = PTR_ERR(vaddr);
638 goto out_unpin;
639 }
640
641 val = prandom_u32_state(&prng);
642
643 memset32(vaddr, val, obj->base.size / sizeof(u32));
644
645 i915_gem_object_flush_map(obj);
646 i915_gem_object_unpin_map(obj);
647out_unpin:
648 i915_gem_object_unpin_pages(obj);
649 __i915_gem_object_put_pages(obj);
650out_put:
651 i915_gem_object_unlock(obj);
652 i915_gem_object_put(obj);
653
654 if (err)
655 break;
656 ++i;
657 } while (!__igt_timeout(end_time, NULL));
658
659 pr_info("%s completed (%u) iterations\n", __func__, i);
660
661 return err;
662}
663
664static int igt_lmem_write_gpu(void *arg)
665{
666 struct drm_i915_private *i915 = arg;
667 struct drm_i915_gem_object *obj;
668 struct i915_gem_context *ctx;
669 struct file *file;
670 I915_RND_STATE(prng);
671 u32 sz;
672 int err;
673
674 file = mock_file(i915);
675 if (IS_ERR(file))
676 return PTR_ERR(file);
677
678 ctx = live_context(i915, file);
679 if (IS_ERR(ctx)) {
680 err = PTR_ERR(ctx);
681 goto out_file;
682 }
683
684 sz = round_up(prandom_u32_state(&prng) % SZ_32M, PAGE_SIZE);
685
686 obj = i915_gem_object_create_lmem(i915, sz, 0);
687 if (IS_ERR(obj)) {
688 err = PTR_ERR(obj);
689 goto out_file;
690 }
691
692 err = i915_gem_object_pin_pages_unlocked(obj);
693 if (err)
694 goto out_put;
695
696 err = igt_gpu_write(ctx, obj);
697 if (err)
698 pr_err("igt_gpu_write failed(%d)\n", err);
699
700 i915_gem_object_unpin_pages(obj);
701out_put:
702 i915_gem_object_put(obj);
703out_file:
704 fput(file);
705 return err;
706}
707
708static struct intel_engine_cs *
709random_engine_class(struct drm_i915_private *i915,
710 unsigned int class,
711 struct rnd_state *prng)
712{
713 struct intel_engine_cs *engine;
714 unsigned int count;
715
716 count = 0;
717 for (engine = intel_engine_lookup_user(i915, class, 0);
718 engine && engine->uabi_class == class;
719 engine = rb_entry_safe(rb_next(&engine->uabi_node),
720 typeof(*engine), uabi_node))
721 count++;
722
723 count = i915_prandom_u32_max_state(count, prng);
724 return intel_engine_lookup_user(i915, class, count);
725}
726
727static int igt_lmem_write_cpu(void *arg)
728{
729 struct drm_i915_private *i915 = arg;
730 struct drm_i915_gem_object *obj;
731 I915_RND_STATE(prng);
732 IGT_TIMEOUT(end_time);
733 u32 bytes[] = {
734 0,
735 sizeof(u32),
736 sizeof(u64),
737 64,
738 PAGE_SIZE,
739 PAGE_SIZE - sizeof(u32),
740 PAGE_SIZE - sizeof(u64),
741 PAGE_SIZE - 64,
742 };
743 struct intel_engine_cs *engine;
744 u32 *vaddr;
745 u32 sz;
746 u32 i;
747 int *order;
748 int count;
749 int err;
750
751 engine = random_engine_class(i915, I915_ENGINE_CLASS_COPY, &prng);
752 if (!engine)
753 return 0;
754
755 pr_info("%s: using %s\n", __func__, engine->name);
756
757 sz = round_up(prandom_u32_state(&prng) % SZ_32M, PAGE_SIZE);
758 sz = max_t(u32, 2 * PAGE_SIZE, sz);
759
760 obj = i915_gem_object_create_lmem(i915, sz, I915_BO_ALLOC_CONTIGUOUS);
761 if (IS_ERR(obj))
762 return PTR_ERR(obj);
763
764 vaddr = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WC);
765 if (IS_ERR(vaddr)) {
766 err = PTR_ERR(vaddr);
767 goto out_put;
768 }
769
770
771 intel_engine_pm_get(engine);
772 err = i915_gem_object_fill_blt(obj, engine->kernel_context, 0xdeadbeaf);
773 intel_engine_pm_put(engine);
774 if (err)
775 goto out_unpin;
776
777 i915_gem_object_lock(obj, NULL);
778 err = i915_gem_object_set_to_wc_domain(obj, true);
779 i915_gem_object_unlock(obj);
780 if (err)
781 goto out_unpin;
782
783 count = ARRAY_SIZE(bytes);
784 order = i915_random_order(count * count, &prng);
785 if (!order) {
786 err = -ENOMEM;
787 goto out_unpin;
788 }
789
790
791 bytes[0] = igt_random_offset(&prng, 64, PAGE_SIZE - 64, 0, sizeof(u32));
792 GEM_BUG_ON(!IS_ALIGNED(bytes[0], sizeof(u32)));
793
794 i = 0;
795 do {
796 u32 offset;
797 u32 align;
798 u32 dword;
799 u32 size;
800 u32 val;
801
802 size = bytes[order[i] % count];
803 i = (i + 1) % (count * count);
804
805 align = bytes[order[i] % count];
806 i = (i + 1) % (count * count);
807
808 align = max_t(u32, sizeof(u32), rounddown_pow_of_two(align));
809
810 offset = igt_random_offset(&prng, 0, obj->base.size,
811 size, align);
812
813 val = prandom_u32_state(&prng);
814 memset32(vaddr + offset / sizeof(u32), val ^ 0xdeadbeaf,
815 size / sizeof(u32));
816
817
818
819
820
821 dword = igt_random_offset(&prng, offset,
822 offset + size,
823 sizeof(u32), sizeof(u32));
824 dword /= sizeof(u32);
825 if (vaddr[dword] != (val ^ 0xdeadbeaf)) {
826 pr_err("%s vaddr[%u]=%u, val=%u, size=%u, align=%u, offset=%u\n",
827 __func__, dword, vaddr[dword], val ^ 0xdeadbeaf,
828 size, align, offset);
829 err = -EINVAL;
830 break;
831 }
832 } while (!__igt_timeout(end_time, NULL));
833
834out_unpin:
835 i915_gem_object_unpin_map(obj);
836out_put:
837 i915_gem_object_put(obj);
838
839 return err;
840}
841
842static const char *repr_type(u32 type)
843{
844 switch (type) {
845 case I915_MAP_WB:
846 return "WB";
847 case I915_MAP_WC:
848 return "WC";
849 }
850
851 return "";
852}
853
854static struct drm_i915_gem_object *
855create_region_for_mapping(struct intel_memory_region *mr, u64 size, u32 type,
856 void **out_addr)
857{
858 struct drm_i915_gem_object *obj;
859 void *addr;
860
861 obj = i915_gem_object_create_region(mr, size, 0);
862 if (IS_ERR(obj)) {
863 if (PTR_ERR(obj) == -ENOSPC)
864 return ERR_PTR(-ENODEV);
865 return obj;
866 }
867
868 addr = i915_gem_object_pin_map_unlocked(obj, type);
869 if (IS_ERR(addr)) {
870 i915_gem_object_put(obj);
871 if (PTR_ERR(addr) == -ENXIO)
872 return ERR_PTR(-ENODEV);
873 return addr;
874 }
875
876 *out_addr = addr;
877 return obj;
878}
879
880static int wrap_ktime_compare(const void *A, const void *B)
881{
882 const ktime_t *a = A, *b = B;
883
884 return ktime_compare(*a, *b);
885}
886
887static void igt_memcpy_long(void *dst, const void *src, size_t size)
888{
889 unsigned long *tmp = dst;
890 const unsigned long *s = src;
891
892 size = size / sizeof(unsigned long);
893 while (size--)
894 *tmp++ = *s++;
895}
896
897static inline void igt_memcpy(void *dst, const void *src, size_t size)
898{
899 memcpy(dst, src, size);
900}
901
902static inline void igt_memcpy_from_wc(void *dst, const void *src, size_t size)
903{
904 i915_memcpy_from_wc(dst, src, size);
905}
906
907static int _perf_memcpy(struct intel_memory_region *src_mr,
908 struct intel_memory_region *dst_mr,
909 u64 size, u32 src_type, u32 dst_type)
910{
911 struct drm_i915_private *i915 = src_mr->i915;
912 const struct {
913 const char *name;
914 void (*copy)(void *dst, const void *src, size_t size);
915 bool skip;
916 } tests[] = {
917 {
918 "memcpy",
919 igt_memcpy,
920 },
921 {
922 "memcpy_long",
923 igt_memcpy_long,
924 },
925 {
926 "memcpy_from_wc",
927 igt_memcpy_from_wc,
928 !i915_has_memcpy_from_wc(),
929 },
930 };
931 struct drm_i915_gem_object *src, *dst;
932 void *src_addr, *dst_addr;
933 int ret = 0;
934 int i;
935
936 src = create_region_for_mapping(src_mr, size, src_type, &src_addr);
937 if (IS_ERR(src)) {
938 ret = PTR_ERR(src);
939 goto out;
940 }
941
942 dst = create_region_for_mapping(dst_mr, size, dst_type, &dst_addr);
943 if (IS_ERR(dst)) {
944 ret = PTR_ERR(dst);
945 goto out_unpin_src;
946 }
947
948 for (i = 0; i < ARRAY_SIZE(tests); ++i) {
949 ktime_t t[5];
950 int pass;
951
952 if (tests[i].skip)
953 continue;
954
955 for (pass = 0; pass < ARRAY_SIZE(t); pass++) {
956 ktime_t t0, t1;
957
958 t0 = ktime_get();
959
960 tests[i].copy(dst_addr, src_addr, size);
961
962 t1 = ktime_get();
963 t[pass] = ktime_sub(t1, t0);
964 }
965
966 sort(t, ARRAY_SIZE(t), sizeof(*t), wrap_ktime_compare, NULL);
967 if (t[0] <= 0) {
968
969 pr_debug("Skipping %s src(%s, %s) -> dst(%s, %s) %14s %4lluKiB copy, unstable measurement [%lld, %lld]\n",
970 __func__,
971 src_mr->name, repr_type(src_type),
972 dst_mr->name, repr_type(dst_type),
973 tests[i].name, size >> 10,
974 t[0], t[4]);
975 continue;
976 }
977
978 pr_info("%s src(%s, %s) -> dst(%s, %s) %14s %4llu KiB copy: %5lld MiB/s\n",
979 __func__,
980 src_mr->name, repr_type(src_type),
981 dst_mr->name, repr_type(dst_type),
982 tests[i].name, size >> 10,
983 div64_u64(mul_u32_u32(4 * size,
984 1000 * 1000 * 1000),
985 t[1] + 2 * t[2] + t[3]) >> 20);
986
987 cond_resched();
988 }
989
990 i915_gem_object_unpin_map(dst);
991 i915_gem_object_put(dst);
992out_unpin_src:
993 i915_gem_object_unpin_map(src);
994 i915_gem_object_put(src);
995
996 i915_gem_drain_freed_objects(i915);
997out:
998 if (ret == -ENODEV)
999 ret = 0;
1000
1001 return ret;
1002}
1003
1004static int perf_memcpy(void *arg)
1005{
1006 struct drm_i915_private *i915 = arg;
1007 static const u32 types[] = {
1008 I915_MAP_WB,
1009 I915_MAP_WC,
1010 };
1011 static const u32 sizes[] = {
1012 SZ_4K,
1013 SZ_64K,
1014 SZ_4M,
1015 };
1016 struct intel_memory_region *src_mr, *dst_mr;
1017 int src_id, dst_id;
1018 int i, j, k;
1019 int ret;
1020
1021 for_each_memory_region(src_mr, i915, src_id) {
1022 for_each_memory_region(dst_mr, i915, dst_id) {
1023 for (i = 0; i < ARRAY_SIZE(sizes); ++i) {
1024 for (j = 0; j < ARRAY_SIZE(types); ++j) {
1025 for (k = 0; k < ARRAY_SIZE(types); ++k) {
1026 ret = _perf_memcpy(src_mr,
1027 dst_mr,
1028 sizes[i],
1029 types[j],
1030 types[k]);
1031 if (ret)
1032 return ret;
1033 }
1034 }
1035 }
1036 }
1037 }
1038
1039 return 0;
1040}
1041
1042int intel_memory_region_mock_selftests(void)
1043{
1044 static const struct i915_subtest tests[] = {
1045 SUBTEST(igt_mock_reserve),
1046 SUBTEST(igt_mock_fill),
1047 SUBTEST(igt_mock_contiguous),
1048 SUBTEST(igt_mock_splintered_region),
1049 };
1050 struct intel_memory_region *mem;
1051 struct drm_i915_private *i915;
1052 int err;
1053
1054 i915 = mock_gem_device();
1055 if (!i915)
1056 return -ENOMEM;
1057
1058 mem = mock_region_create(i915, 0, SZ_2G, I915_GTT_PAGE_SIZE_4K, 0);
1059 if (IS_ERR(mem)) {
1060 pr_err("failed to create memory region\n");
1061 err = PTR_ERR(mem);
1062 goto out_unref;
1063 }
1064
1065 err = i915_subtests(tests, mem);
1066
1067 intel_memory_region_put(mem);
1068out_unref:
1069 mock_destroy_device(i915);
1070 return err;
1071}
1072
1073int intel_memory_region_live_selftests(struct drm_i915_private *i915)
1074{
1075 static const struct i915_subtest tests[] = {
1076 SUBTEST(igt_lmem_create),
1077 SUBTEST(igt_lmem_create_cleared_cpu),
1078 SUBTEST(igt_lmem_write_cpu),
1079 SUBTEST(igt_lmem_write_gpu),
1080 };
1081
1082 if (!HAS_LMEM(i915)) {
1083 pr_info("device lacks LMEM support, skipping\n");
1084 return 0;
1085 }
1086
1087 if (intel_gt_is_wedged(&i915->gt))
1088 return 0;
1089
1090 return i915_live_subtests(tests, i915);
1091}
1092
1093int intel_memory_region_perf_selftests(struct drm_i915_private *i915)
1094{
1095 static const struct i915_subtest tests[] = {
1096 SUBTEST(perf_memcpy),
1097 };
1098
1099 if (intel_gt_is_wedged(&i915->gt))
1100 return 0;
1101
1102 return i915_live_subtests(tests, i915);
1103}
1104