1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2020-2021 Intel Corporation
4  */
5 
6 #include "gt/intel_migrate.h"
7 
8 static int igt_fill_check_buffer(struct drm_i915_gem_object *obj,
9 				 bool fill)
10 {
11 	struct drm_i915_private *i915 = to_i915(obj->base.dev);
12 	unsigned int i, count = obj->base.size / sizeof(u32);
13 	enum i915_map_type map_type =
14 		i915_coherent_map_type(i915, obj, false);
15 	u32 *cur;
16 	int err = 0;
17 
18 	assert_object_held(obj);
19 	cur = i915_gem_object_pin_map(obj, map_type);
20 	if (IS_ERR(cur))
21 		return PTR_ERR(cur);
22 
23 	if (fill)
24 		for (i = 0; i < count; ++i)
25 			*cur++ = i;
26 	else
27 		for (i = 0; i < count; ++i)
28 			if (*cur++ != i) {
29 				pr_err("Object content mismatch at location %d of %d\n", i, count);
30 				err = -EINVAL;
31 				break;
32 			}
33 
34 	i915_gem_object_unpin_map(obj);
35 
36 	return err;
37 }
38 
39 static int igt_create_migrate(struct intel_gt *gt, enum intel_region_id src,
40 			      enum intel_region_id dst)
41 {
42 	struct drm_i915_private *i915 = gt->i915;
43 	struct intel_memory_region *src_mr = i915->mm.regions[src];
44 	struct drm_i915_gem_object *obj;
45 	struct i915_gem_ww_ctx ww;
46 	int err = 0;
47 
48 	GEM_BUG_ON(!src_mr);
49 
50 	/* Switch object backing-store on create */
51 	obj = i915_gem_object_create_region(src_mr, PAGE_SIZE, 0, 0);
52 	if (IS_ERR(obj))
53 		return PTR_ERR(obj);
54 
55 	for_i915_gem_ww(&ww, err, true) {
56 		err = i915_gem_object_lock(obj, &ww);
57 		if (err)
58 			continue;
59 
60 		err = igt_fill_check_buffer(obj, true);
61 		if (err)
62 			continue;
63 
64 		err = i915_gem_object_migrate(obj, &ww, dst);
65 		if (err)
66 			continue;
67 
68 		err = i915_gem_object_pin_pages(obj);
69 		if (err)
70 			continue;
71 
72 		if (i915_gem_object_can_migrate(obj, src))
73 			err = -EINVAL;
74 
75 		i915_gem_object_unpin_pages(obj);
76 		err = i915_gem_object_wait_migration(obj, true);
77 		if (err)
78 			continue;
79 
80 		err = igt_fill_check_buffer(obj, false);
81 	}
82 	i915_gem_object_put(obj);
83 
84 	return err;
85 }
86 
87 static int igt_smem_create_migrate(void *arg)
88 {
89 	return igt_create_migrate(arg, INTEL_REGION_LMEM, INTEL_REGION_SMEM);
90 }
91 
92 static int igt_lmem_create_migrate(void *arg)
93 {
94 	return igt_create_migrate(arg, INTEL_REGION_SMEM, INTEL_REGION_LMEM);
95 }
96 
97 static int igt_same_create_migrate(void *arg)
98 {
99 	return igt_create_migrate(arg, INTEL_REGION_LMEM, INTEL_REGION_LMEM);
100 }
101 
102 static int lmem_pages_migrate_one(struct i915_gem_ww_ctx *ww,
103 				  struct drm_i915_gem_object *obj)
104 {
105 	int err;
106 
107 	err = i915_gem_object_lock(obj, ww);
108 	if (err)
109 		return err;
110 
111 	if (i915_gem_object_is_lmem(obj)) {
112 		err = i915_gem_object_migrate(obj, ww, INTEL_REGION_SMEM);
113 		if (err) {
114 			pr_err("Object failed migration to smem\n");
115 			if (err)
116 				return err;
117 		}
118 
119 		if (i915_gem_object_is_lmem(obj)) {
120 			pr_err("object still backed by lmem\n");
121 			err = -EINVAL;
122 		}
123 
124 		if (!i915_gem_object_has_struct_page(obj)) {
125 			pr_err("object not backed by struct page\n");
126 			err = -EINVAL;
127 		}
128 
129 	} else {
130 		err = i915_gem_object_migrate(obj, ww, INTEL_REGION_LMEM);
131 		if (err) {
132 			pr_err("Object failed migration to lmem\n");
133 			if (err)
134 				return err;
135 		}
136 
137 		if (i915_gem_object_has_struct_page(obj)) {
138 			pr_err("object still backed by struct page\n");
139 			err = -EINVAL;
140 		}
141 
142 		if (!i915_gem_object_is_lmem(obj)) {
143 			pr_err("object not backed by lmem\n");
144 			err = -EINVAL;
145 		}
146 	}
147 
148 	return err;
149 }
150 
151 static int igt_lmem_pages_migrate(void *arg)
152 {
153 	struct intel_gt *gt = arg;
154 	struct drm_i915_private *i915 = gt->i915;
155 	struct drm_i915_gem_object *obj;
156 	struct i915_gem_ww_ctx ww;
157 	struct i915_request *rq;
158 	int err;
159 	int i;
160 
161 	/* From LMEM to shmem and back again */
162 
163 	obj = i915_gem_object_create_lmem(i915, SZ_2M, 0);
164 	if (IS_ERR(obj))
165 		return PTR_ERR(obj);
166 
167 	/* Initial GPU fill, sync, CPU initialization. */
168 	for_i915_gem_ww(&ww, err, true) {
169 		err = i915_gem_object_lock(obj, &ww);
170 		if (err)
171 			continue;
172 
173 		err = ____i915_gem_object_get_pages(obj);
174 		if (err)
175 			continue;
176 
177 		err = intel_migrate_clear(&gt->migrate, &ww, NULL,
178 					  obj->mm.pages->sgl, obj->cache_level,
179 					  i915_gem_object_is_lmem(obj),
180 					  0xdeadbeaf, &rq);
181 		if (rq) {
182 			dma_resv_add_excl_fence(obj->base.resv, &rq->fence);
183 			i915_request_put(rq);
184 		}
185 		if (err)
186 			continue;
187 
188 		err = i915_gem_object_wait(obj, I915_WAIT_INTERRUPTIBLE,
189 					   5 * HZ);
190 		if (err)
191 			continue;
192 
193 		err = igt_fill_check_buffer(obj, true);
194 		if (err)
195 			continue;
196 	}
197 	if (err)
198 		goto out_put;
199 
200 	/*
201 	 * Migrate to and from smem without explicitly syncing.
202 	 * Finalize with data in smem for fast readout.
203 	 */
204 	for (i = 1; i <= 5; ++i) {
205 		for_i915_gem_ww(&ww, err, true)
206 			err = lmem_pages_migrate_one(&ww, obj);
207 		if (err)
208 			goto out_put;
209 	}
210 
211 	err = i915_gem_object_lock_interruptible(obj, NULL);
212 	if (err)
213 		goto out_put;
214 
215 	/* Finally sync migration and check content. */
216 	err = i915_gem_object_wait_migration(obj, true);
217 	if (err)
218 		goto out_unlock;
219 
220 	err = igt_fill_check_buffer(obj, false);
221 
222 out_unlock:
223 	i915_gem_object_unlock(obj);
224 out_put:
225 	i915_gem_object_put(obj);
226 
227 	return err;
228 }
229 
230 int i915_gem_migrate_live_selftests(struct drm_i915_private *i915)
231 {
232 	static const struct i915_subtest tests[] = {
233 		SUBTEST(igt_smem_create_migrate),
234 		SUBTEST(igt_lmem_create_migrate),
235 		SUBTEST(igt_same_create_migrate),
236 		SUBTEST(igt_lmem_pages_migrate),
237 	};
238 
239 	if (!HAS_LMEM(i915))
240 		return 0;
241 
242 	return intel_gt_live_subtests(tests, &i915->gt);
243 }
244