1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2020 Intel Corporation
4  */
5 
6 #include "i915_selftest.h"
7 
8 #include "gt/intel_engine_pm.h"
9 #include "selftests/igt_flush_test.h"
10 
read_reloc(const u32 * map,int x,const u64 mask)11 static u64 read_reloc(const u32 *map, int x, const u64 mask)
12 {
13 	u64 reloc;
14 
15 	memcpy(&reloc, &map[x], sizeof(reloc));
16 	return reloc & mask;
17 }
18 
__igt_gpu_reloc(struct i915_execbuffer * eb,struct drm_i915_gem_object * obj)19 static int __igt_gpu_reloc(struct i915_execbuffer *eb,
20 			   struct drm_i915_gem_object *obj)
21 {
22 	const unsigned int offsets[] = { 8, 3, 0 };
23 	const u64 mask =
24 		GENMASK_ULL(eb->reloc_cache.use_64bit_reloc ? 63 : 31, 0);
25 	const u32 *map = page_mask_bits(obj->mm.mapping);
26 	struct i915_request *rq;
27 	struct i915_vma *vma;
28 	int err;
29 	int i;
30 
31 	vma = i915_vma_instance(obj, eb->context->vm, NULL);
32 	if (IS_ERR(vma))
33 		return PTR_ERR(vma);
34 
35 	err = i915_gem_object_lock(obj, &eb->ww);
36 	if (err)
37 		return err;
38 
39 	err = i915_vma_pin_ww(vma, &eb->ww, 0, 0, PIN_USER | PIN_HIGH);
40 	if (err)
41 		return err;
42 
43 	/* 8-Byte aligned */
44 	err = __reloc_entry_gpu(eb, vma, offsets[0] * sizeof(u32), 0);
45 	if (err <= 0)
46 		goto reloc_err;
47 
48 	/* !8-Byte aligned */
49 	err = __reloc_entry_gpu(eb, vma, offsets[1] * sizeof(u32), 1);
50 	if (err <= 0)
51 		goto reloc_err;
52 
53 	/* Skip to the end of the cmd page */
54 	i = PAGE_SIZE / sizeof(u32) - 1;
55 	i -= eb->reloc_cache.rq_size;
56 	memset32(eb->reloc_cache.rq_cmd + eb->reloc_cache.rq_size,
57 		 MI_NOOP, i);
58 	eb->reloc_cache.rq_size += i;
59 
60 	/* Force next batch */
61 	err = __reloc_entry_gpu(eb, vma, offsets[2] * sizeof(u32), 2);
62 	if (err <= 0)
63 		goto reloc_err;
64 
65 	GEM_BUG_ON(!eb->reloc_cache.rq);
66 	rq = i915_request_get(eb->reloc_cache.rq);
67 	reloc_gpu_flush(eb, &eb->reloc_cache);
68 	GEM_BUG_ON(eb->reloc_cache.rq);
69 
70 	err = i915_gem_object_wait(obj, I915_WAIT_INTERRUPTIBLE, HZ / 2);
71 	if (err) {
72 		intel_gt_set_wedged(eb->engine->gt);
73 		goto put_rq;
74 	}
75 
76 	if (!i915_request_completed(rq)) {
77 		pr_err("%s: did not wait for relocations!\n", eb->engine->name);
78 		err = -EINVAL;
79 		goto put_rq;
80 	}
81 
82 	for (i = 0; i < ARRAY_SIZE(offsets); i++) {
83 		u64 reloc = read_reloc(map, offsets[i], mask);
84 
85 		if (reloc != i) {
86 			pr_err("%s[%d]: map[%d] %llx != %x\n",
87 			       eb->engine->name, i, offsets[i], reloc, i);
88 			err = -EINVAL;
89 		}
90 	}
91 	if (err)
92 		igt_hexdump(map, 4096);
93 
94 put_rq:
95 	i915_request_put(rq);
96 unpin_vma:
97 	i915_vma_unpin(vma);
98 	return err;
99 
100 reloc_err:
101 	if (!err)
102 		err = -EIO;
103 	goto unpin_vma;
104 }
105 
igt_gpu_reloc(void * arg)106 static int igt_gpu_reloc(void *arg)
107 {
108 	struct i915_execbuffer eb;
109 	struct drm_i915_gem_object *scratch;
110 	int err = 0;
111 	u32 *map;
112 
113 	eb.i915 = arg;
114 
115 	scratch = i915_gem_object_create_internal(eb.i915, 4096);
116 	if (IS_ERR(scratch))
117 		return PTR_ERR(scratch);
118 
119 	map = i915_gem_object_pin_map(scratch, I915_MAP_WC);
120 	if (IS_ERR(map)) {
121 		err = PTR_ERR(map);
122 		goto err_scratch;
123 	}
124 
125 	intel_gt_pm_get(&eb.i915->gt);
126 
127 	for_each_uabi_engine(eb.engine, eb.i915) {
128 		reloc_cache_init(&eb.reloc_cache, eb.i915);
129 		memset(map, POISON_INUSE, 4096);
130 
131 		intel_engine_pm_get(eb.engine);
132 		eb.context = intel_context_create(eb.engine);
133 		if (IS_ERR(eb.context)) {
134 			err = PTR_ERR(eb.context);
135 			goto err_pm;
136 		}
137 		eb.reloc_pool = NULL;
138 		eb.reloc_context = NULL;
139 
140 		i915_gem_ww_ctx_init(&eb.ww, false);
141 retry:
142 		err = intel_context_pin_ww(eb.context, &eb.ww);
143 		if (!err) {
144 			err = __igt_gpu_reloc(&eb, scratch);
145 
146 			intel_context_unpin(eb.context);
147 		}
148 		if (err == -EDEADLK) {
149 			err = i915_gem_ww_ctx_backoff(&eb.ww);
150 			if (!err)
151 				goto retry;
152 		}
153 		i915_gem_ww_ctx_fini(&eb.ww);
154 
155 		if (eb.reloc_pool)
156 			intel_gt_buffer_pool_put(eb.reloc_pool);
157 		if (eb.reloc_context)
158 			intel_context_put(eb.reloc_context);
159 
160 		intel_context_put(eb.context);
161 err_pm:
162 		intel_engine_pm_put(eb.engine);
163 		if (err)
164 			break;
165 	}
166 
167 	if (igt_flush_test(eb.i915))
168 		err = -EIO;
169 
170 	intel_gt_pm_put(&eb.i915->gt);
171 err_scratch:
172 	i915_gem_object_put(scratch);
173 	return err;
174 }
175 
i915_gem_execbuffer_live_selftests(struct drm_i915_private * i915)176 int i915_gem_execbuffer_live_selftests(struct drm_i915_private *i915)
177 {
178 	static const struct i915_subtest tests[] = {
179 		SUBTEST(igt_gpu_reloc),
180 	};
181 
182 	if (intel_gt_is_wedged(&i915->gt))
183 		return 0;
184 
185 	return i915_live_subtests(tests, i915);
186 }
187