1 /*
2  * SPDX-License-Identifier: MIT
3  *
4  * Copyright © 2016 Intel Corporation
5  */
6 
7 #include "i915_drv.h"
8 #include "i915_selftest.h"
9 
10 #include "mock_dmabuf.h"
11 #include "selftests/mock_gem_device.h"
12 
13 static int igt_dmabuf_export(void *arg)
14 {
15 	struct drm_i915_private *i915 = arg;
16 	struct drm_i915_gem_object *obj;
17 	struct dma_buf *dmabuf;
18 
19 	obj = i915_gem_object_create_shmem(i915, PAGE_SIZE);
20 	if (IS_ERR(obj))
21 		return PTR_ERR(obj);
22 
23 	dmabuf = i915_gem_prime_export(&i915->drm, &obj->base, 0);
24 	i915_gem_object_put(obj);
25 	if (IS_ERR(dmabuf)) {
26 		pr_err("i915_gem_prime_export failed with err=%d\n",
27 		       (int)PTR_ERR(dmabuf));
28 		return PTR_ERR(dmabuf);
29 	}
30 
31 	dma_buf_put(dmabuf);
32 	return 0;
33 }
34 
35 static int igt_dmabuf_import_self(void *arg)
36 {
37 	struct drm_i915_private *i915 = arg;
38 	struct drm_i915_gem_object *obj;
39 	struct drm_gem_object *import;
40 	struct dma_buf *dmabuf;
41 	int err;
42 
43 	obj = i915_gem_object_create_shmem(i915, PAGE_SIZE);
44 	if (IS_ERR(obj))
45 		return PTR_ERR(obj);
46 
47 	dmabuf = i915_gem_prime_export(&i915->drm, &obj->base, 0);
48 	if (IS_ERR(dmabuf)) {
49 		pr_err("i915_gem_prime_export failed with err=%d\n",
50 		       (int)PTR_ERR(dmabuf));
51 		err = PTR_ERR(dmabuf);
52 		goto out;
53 	}
54 
55 	import = i915_gem_prime_import(&i915->drm, dmabuf);
56 	if (IS_ERR(import)) {
57 		pr_err("i915_gem_prime_import failed with err=%d\n",
58 		       (int)PTR_ERR(import));
59 		err = PTR_ERR(import);
60 		goto out_dmabuf;
61 	}
62 
63 	if (import != &obj->base) {
64 		pr_err("i915_gem_prime_import created a new object!\n");
65 		err = -EINVAL;
66 		goto out_import;
67 	}
68 
69 	err = 0;
70 out_import:
71 	i915_gem_object_put(to_intel_bo(import));
72 out_dmabuf:
73 	dma_buf_put(dmabuf);
74 out:
75 	i915_gem_object_put(obj);
76 	return err;
77 }
78 
79 static int igt_dmabuf_import(void *arg)
80 {
81 	struct drm_i915_private *i915 = arg;
82 	struct drm_i915_gem_object *obj;
83 	struct dma_buf *dmabuf;
84 	void *obj_map, *dma_map;
85 	u32 pattern[] = { 0, 0xaa, 0xcc, 0x55, 0xff };
86 	int err, i;
87 
88 	dmabuf = mock_dmabuf(1);
89 	if (IS_ERR(dmabuf))
90 		return PTR_ERR(dmabuf);
91 
92 	obj = to_intel_bo(i915_gem_prime_import(&i915->drm, dmabuf));
93 	if (IS_ERR(obj)) {
94 		pr_err("i915_gem_prime_import failed with err=%d\n",
95 		       (int)PTR_ERR(obj));
96 		err = PTR_ERR(obj);
97 		goto out_dmabuf;
98 	}
99 
100 	if (obj->base.dev != &i915->drm) {
101 		pr_err("i915_gem_prime_import created a non-i915 object!\n");
102 		err = -EINVAL;
103 		goto out_obj;
104 	}
105 
106 	if (obj->base.size != PAGE_SIZE) {
107 		pr_err("i915_gem_prime_import is wrong size found %lld, expected %ld\n",
108 		       (long long)obj->base.size, PAGE_SIZE);
109 		err = -EINVAL;
110 		goto out_obj;
111 	}
112 
113 	dma_map = dma_buf_vmap(dmabuf);
114 	if (!dma_map) {
115 		pr_err("dma_buf_vmap failed\n");
116 		err = -ENOMEM;
117 		goto out_obj;
118 	}
119 
120 	if (0) { /* Can not yet map dmabuf */
121 		obj_map = i915_gem_object_pin_map(obj, I915_MAP_WB);
122 		if (IS_ERR(obj_map)) {
123 			err = PTR_ERR(obj_map);
124 			pr_err("i915_gem_object_pin_map failed with err=%d\n", err);
125 			goto out_dma_map;
126 		}
127 
128 		for (i = 0; i < ARRAY_SIZE(pattern); i++) {
129 			memset(dma_map, pattern[i], PAGE_SIZE);
130 			if (memchr_inv(obj_map, pattern[i], PAGE_SIZE)) {
131 				err = -EINVAL;
132 				pr_err("imported vmap not all set to %x!\n", pattern[i]);
133 				i915_gem_object_unpin_map(obj);
134 				goto out_dma_map;
135 			}
136 		}
137 
138 		for (i = 0; i < ARRAY_SIZE(pattern); i++) {
139 			memset(obj_map, pattern[i], PAGE_SIZE);
140 			if (memchr_inv(dma_map, pattern[i], PAGE_SIZE)) {
141 				err = -EINVAL;
142 				pr_err("exported vmap not all set to %x!\n", pattern[i]);
143 				i915_gem_object_unpin_map(obj);
144 				goto out_dma_map;
145 			}
146 		}
147 
148 		i915_gem_object_unpin_map(obj);
149 	}
150 
151 	err = 0;
152 out_dma_map:
153 	dma_buf_vunmap(dmabuf, dma_map);
154 out_obj:
155 	i915_gem_object_put(obj);
156 out_dmabuf:
157 	dma_buf_put(dmabuf);
158 	return err;
159 }
160 
161 static int igt_dmabuf_import_ownership(void *arg)
162 {
163 	struct drm_i915_private *i915 = arg;
164 	struct drm_i915_gem_object *obj;
165 	struct dma_buf *dmabuf;
166 	void *ptr;
167 	int err;
168 
169 	dmabuf = mock_dmabuf(1);
170 	if (IS_ERR(dmabuf))
171 		return PTR_ERR(dmabuf);
172 
173 	ptr = dma_buf_vmap(dmabuf);
174 	if (!ptr) {
175 		pr_err("dma_buf_vmap failed\n");
176 		err = -ENOMEM;
177 		goto err_dmabuf;
178 	}
179 
180 	memset(ptr, 0xc5, PAGE_SIZE);
181 	dma_buf_vunmap(dmabuf, ptr);
182 
183 	obj = to_intel_bo(i915_gem_prime_import(&i915->drm, dmabuf));
184 	if (IS_ERR(obj)) {
185 		pr_err("i915_gem_prime_import failed with err=%d\n",
186 		       (int)PTR_ERR(obj));
187 		err = PTR_ERR(obj);
188 		goto err_dmabuf;
189 	}
190 
191 	dma_buf_put(dmabuf);
192 
193 	err = i915_gem_object_pin_pages(obj);
194 	if (err) {
195 		pr_err("i915_gem_object_pin_pages failed with err=%d\n", err);
196 		goto out_obj;
197 	}
198 
199 	err = 0;
200 	i915_gem_object_unpin_pages(obj);
201 out_obj:
202 	i915_gem_object_put(obj);
203 	return err;
204 
205 err_dmabuf:
206 	dma_buf_put(dmabuf);
207 	return err;
208 }
209 
210 static int igt_dmabuf_export_vmap(void *arg)
211 {
212 	struct drm_i915_private *i915 = arg;
213 	struct drm_i915_gem_object *obj;
214 	struct dma_buf *dmabuf;
215 	void *ptr;
216 	int err;
217 
218 	obj = i915_gem_object_create_shmem(i915, PAGE_SIZE);
219 	if (IS_ERR(obj))
220 		return PTR_ERR(obj);
221 
222 	dmabuf = i915_gem_prime_export(&i915->drm, &obj->base, 0);
223 	if (IS_ERR(dmabuf)) {
224 		pr_err("i915_gem_prime_export failed with err=%d\n",
225 		       (int)PTR_ERR(dmabuf));
226 		err = PTR_ERR(dmabuf);
227 		goto err_obj;
228 	}
229 	i915_gem_object_put(obj);
230 
231 	ptr = dma_buf_vmap(dmabuf);
232 	if (!ptr) {
233 		pr_err("dma_buf_vmap failed\n");
234 		err = -ENOMEM;
235 		goto out;
236 	}
237 
238 	if (memchr_inv(ptr, 0, dmabuf->size)) {
239 		pr_err("Exported object not initialiased to zero!\n");
240 		err = -EINVAL;
241 		goto out;
242 	}
243 
244 	memset(ptr, 0xc5, dmabuf->size);
245 
246 	err = 0;
247 	dma_buf_vunmap(dmabuf, ptr);
248 out:
249 	dma_buf_put(dmabuf);
250 	return err;
251 
252 err_obj:
253 	i915_gem_object_put(obj);
254 	return err;
255 }
256 
257 static int igt_dmabuf_export_kmap(void *arg)
258 {
259 	struct drm_i915_private *i915 = arg;
260 	struct drm_i915_gem_object *obj;
261 	struct dma_buf *dmabuf;
262 	void *ptr;
263 	int err;
264 
265 	obj = i915_gem_object_create_shmem(i915, 2 * PAGE_SIZE);
266 	if (IS_ERR(obj))
267 		return PTR_ERR(obj);
268 
269 	dmabuf = i915_gem_prime_export(&i915->drm, &obj->base, 0);
270 	i915_gem_object_put(obj);
271 	if (IS_ERR(dmabuf)) {
272 		err = PTR_ERR(dmabuf);
273 		pr_err("i915_gem_prime_export failed with err=%d\n", err);
274 		return err;
275 	}
276 
277 	ptr = dma_buf_kmap(dmabuf, 0);
278 	if (!ptr) {
279 		pr_err("dma_buf_kmap failed\n");
280 		err = -ENOMEM;
281 		goto err;
282 	}
283 
284 	if (memchr_inv(ptr, 0, PAGE_SIZE)) {
285 		dma_buf_kunmap(dmabuf, 0, ptr);
286 		pr_err("Exported page[0] not initialiased to zero!\n");
287 		err = -EINVAL;
288 		goto err;
289 	}
290 
291 	memset(ptr, 0xc5, PAGE_SIZE);
292 	dma_buf_kunmap(dmabuf, 0, ptr);
293 
294 	ptr = i915_gem_object_pin_map(obj, I915_MAP_WB);
295 	if (IS_ERR(ptr)) {
296 		err = PTR_ERR(ptr);
297 		pr_err("i915_gem_object_pin_map failed with err=%d\n", err);
298 		goto err;
299 	}
300 	memset(ptr + PAGE_SIZE, 0xaa, PAGE_SIZE);
301 	i915_gem_object_flush_map(obj);
302 	i915_gem_object_unpin_map(obj);
303 
304 	ptr = dma_buf_kmap(dmabuf, 1);
305 	if (!ptr) {
306 		pr_err("dma_buf_kmap failed\n");
307 		err = -ENOMEM;
308 		goto err;
309 	}
310 
311 	if (memchr_inv(ptr, 0xaa, PAGE_SIZE)) {
312 		dma_buf_kunmap(dmabuf, 1, ptr);
313 		pr_err("Exported page[1] not set to 0xaa!\n");
314 		err = -EINVAL;
315 		goto err;
316 	}
317 
318 	memset(ptr, 0xc5, PAGE_SIZE);
319 	dma_buf_kunmap(dmabuf, 1, ptr);
320 
321 	ptr = dma_buf_kmap(dmabuf, 0);
322 	if (!ptr) {
323 		pr_err("dma_buf_kmap failed\n");
324 		err = -ENOMEM;
325 		goto err;
326 	}
327 	if (memchr_inv(ptr, 0xc5, PAGE_SIZE)) {
328 		dma_buf_kunmap(dmabuf, 0, ptr);
329 		pr_err("Exported page[0] did not retain 0xc5!\n");
330 		err = -EINVAL;
331 		goto err;
332 	}
333 	dma_buf_kunmap(dmabuf, 0, ptr);
334 
335 	ptr = dma_buf_kmap(dmabuf, 2);
336 	if (ptr) {
337 		pr_err("Erroneously kmapped beyond the end of the object!\n");
338 		dma_buf_kunmap(dmabuf, 2, ptr);
339 		err = -EINVAL;
340 		goto err;
341 	}
342 
343 	ptr = dma_buf_kmap(dmabuf, -1);
344 	if (ptr) {
345 		pr_err("Erroneously kmapped before the start of the object!\n");
346 		dma_buf_kunmap(dmabuf, -1, ptr);
347 		err = -EINVAL;
348 		goto err;
349 	}
350 
351 	err = 0;
352 err:
353 	dma_buf_put(dmabuf);
354 	return err;
355 }
356 
357 int i915_gem_dmabuf_mock_selftests(void)
358 {
359 	static const struct i915_subtest tests[] = {
360 		SUBTEST(igt_dmabuf_export),
361 		SUBTEST(igt_dmabuf_import_self),
362 		SUBTEST(igt_dmabuf_import),
363 		SUBTEST(igt_dmabuf_import_ownership),
364 		SUBTEST(igt_dmabuf_export_vmap),
365 		SUBTEST(igt_dmabuf_export_kmap),
366 	};
367 	struct drm_i915_private *i915;
368 	int err;
369 
370 	i915 = mock_gem_device();
371 	if (!i915)
372 		return -ENOMEM;
373 
374 	err = i915_subtests(tests, i915);
375 
376 	drm_dev_put(&i915->drm);
377 	return err;
378 }
379 
380 int i915_gem_dmabuf_live_selftests(struct drm_i915_private *i915)
381 {
382 	static const struct i915_subtest tests[] = {
383 		SUBTEST(igt_dmabuf_export),
384 	};
385 
386 	return i915_subtests(tests, i915);
387 }
388