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 #include "gem/i915_gem_context.h"
10 
11 #include "mock_context.h"
12 #include "mock_dmabuf.h"
13 #include "igt_gem_utils.h"
14 #include "selftests/mock_drm.h"
15 #include "selftests/mock_gem_device.h"
16 
17 static int igt_dmabuf_export(void *arg)
18 {
19 	struct drm_i915_private *i915 = arg;
20 	struct drm_i915_gem_object *obj;
21 	struct dma_buf *dmabuf;
22 
23 	obj = i915_gem_object_create_shmem(i915, PAGE_SIZE);
24 	if (IS_ERR(obj))
25 		return PTR_ERR(obj);
26 
27 	dmabuf = i915_gem_prime_export(&obj->base, 0);
28 	i915_gem_object_put(obj);
29 	if (IS_ERR(dmabuf)) {
30 		pr_err("i915_gem_prime_export failed with err=%d\n",
31 		       (int)PTR_ERR(dmabuf));
32 		return PTR_ERR(dmabuf);
33 	}
34 
35 	dma_buf_put(dmabuf);
36 	return 0;
37 }
38 
39 static int igt_dmabuf_import_self(void *arg)
40 {
41 	struct drm_i915_private *i915 = arg;
42 	struct drm_i915_gem_object *obj, *import_obj;
43 	struct drm_gem_object *import;
44 	struct dma_buf *dmabuf;
45 	int err;
46 
47 	obj = i915_gem_object_create_shmem(i915, PAGE_SIZE);
48 	if (IS_ERR(obj))
49 		return PTR_ERR(obj);
50 
51 	dmabuf = i915_gem_prime_export(&obj->base, 0);
52 	if (IS_ERR(dmabuf)) {
53 		pr_err("i915_gem_prime_export failed with err=%d\n",
54 		       (int)PTR_ERR(dmabuf));
55 		err = PTR_ERR(dmabuf);
56 		goto out;
57 	}
58 
59 	import = i915_gem_prime_import(&i915->drm, dmabuf);
60 	if (IS_ERR(import)) {
61 		pr_err("i915_gem_prime_import failed with err=%d\n",
62 		       (int)PTR_ERR(import));
63 		err = PTR_ERR(import);
64 		goto out_dmabuf;
65 	}
66 	import_obj = to_intel_bo(import);
67 
68 	if (import != &obj->base) {
69 		pr_err("i915_gem_prime_import created a new object!\n");
70 		err = -EINVAL;
71 		goto out_import;
72 	}
73 
74 	i915_gem_object_lock(import_obj, NULL);
75 	err = __i915_gem_object_get_pages(import_obj);
76 	i915_gem_object_unlock(import_obj);
77 	if (err) {
78 		pr_err("Same object dma-buf get_pages failed!\n");
79 		goto out_import;
80 	}
81 
82 	err = 0;
83 out_import:
84 	i915_gem_object_put(import_obj);
85 out_dmabuf:
86 	dma_buf_put(dmabuf);
87 out:
88 	i915_gem_object_put(obj);
89 	return err;
90 }
91 
92 static int igt_dmabuf_import_same_driver_lmem(void *arg)
93 {
94 	struct drm_i915_private *i915 = arg;
95 	struct intel_memory_region *lmem = i915->mm.regions[INTEL_REGION_LMEM_0];
96 	struct drm_i915_gem_object *obj;
97 	struct drm_gem_object *import;
98 	struct dma_buf *dmabuf;
99 	int err;
100 
101 	if (!lmem)
102 		return 0;
103 
104 	force_different_devices = true;
105 
106 	obj = __i915_gem_object_create_user(i915, PAGE_SIZE, &lmem, 1);
107 	if (IS_ERR(obj)) {
108 		pr_err("__i915_gem_object_create_user failed with err=%ld\n",
109 		       PTR_ERR(obj));
110 		err = PTR_ERR(obj);
111 		goto out_ret;
112 	}
113 
114 	dmabuf = i915_gem_prime_export(&obj->base, 0);
115 	if (IS_ERR(dmabuf)) {
116 		pr_err("i915_gem_prime_export failed with err=%ld\n",
117 		       PTR_ERR(dmabuf));
118 		err = PTR_ERR(dmabuf);
119 		goto out;
120 	}
121 
122 	/*
123 	 * We expect an import of an LMEM-only object to fail with
124 	 * -EOPNOTSUPP because it can't be migrated to SMEM.
125 	 */
126 	import = i915_gem_prime_import(&i915->drm, dmabuf);
127 	if (!IS_ERR(import)) {
128 		drm_gem_object_put(import);
129 		pr_err("i915_gem_prime_import succeeded when it shouldn't have\n");
130 		err = -EINVAL;
131 	} else if (PTR_ERR(import) != -EOPNOTSUPP) {
132 		pr_err("i915_gem_prime_import failed with the wrong err=%ld\n",
133 		       PTR_ERR(import));
134 		err = PTR_ERR(import);
135 	} else {
136 		err = 0;
137 	}
138 
139 	dma_buf_put(dmabuf);
140 out:
141 	i915_gem_object_put(obj);
142 out_ret:
143 	force_different_devices = false;
144 	return err;
145 }
146 
147 static int verify_access(struct drm_i915_private *i915,
148 			 struct drm_i915_gem_object *native_obj,
149 			 struct drm_i915_gem_object *import_obj)
150 {
151 	struct i915_gem_engines_iter it;
152 	struct i915_gem_context *ctx;
153 	struct intel_context *ce;
154 	struct i915_vma *vma;
155 	struct file *file;
156 	u32 *vaddr;
157 	int err = 0, i;
158 
159 	file = mock_file(i915);
160 	if (IS_ERR(file))
161 		return PTR_ERR(file);
162 
163 	ctx = live_context(i915, file);
164 	if (IS_ERR(ctx)) {
165 		err = PTR_ERR(ctx);
166 		goto out_file;
167 	}
168 
169 	for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it) {
170 		if (intel_engine_can_store_dword(ce->engine))
171 			break;
172 	}
173 	i915_gem_context_unlock_engines(ctx);
174 	if (!ce)
175 		goto out_file;
176 
177 	vma = i915_vma_instance(import_obj, ce->vm, NULL);
178 	if (IS_ERR(vma)) {
179 		err = PTR_ERR(vma);
180 		goto out_file;
181 	}
182 
183 	err = i915_vma_pin(vma, 0, 0, PIN_USER);
184 	if (err)
185 		goto out_file;
186 
187 	err = igt_gpu_fill_dw(ce, vma, 0,
188 			      vma->size >> PAGE_SHIFT, 0xdeadbeaf);
189 	i915_vma_unpin(vma);
190 	if (err)
191 		goto out_file;
192 
193 	err = i915_gem_object_wait(import_obj, 0, MAX_SCHEDULE_TIMEOUT);
194 	if (err)
195 		goto out_file;
196 
197 	vaddr = i915_gem_object_pin_map_unlocked(native_obj, I915_MAP_WB);
198 	if (IS_ERR(vaddr)) {
199 		err = PTR_ERR(vaddr);
200 		goto out_file;
201 	}
202 
203 	for (i = 0; i < native_obj->base.size / sizeof(u32); i += PAGE_SIZE / sizeof(u32)) {
204 		if (vaddr[i] != 0xdeadbeaf) {
205 			pr_err("Data mismatch [%d]=%u\n", i, vaddr[i]);
206 			err = -EINVAL;
207 			goto out_file;
208 		}
209 	}
210 
211 out_file:
212 	fput(file);
213 	return err;
214 }
215 
216 static int igt_dmabuf_import_same_driver(struct drm_i915_private *i915,
217 					 struct intel_memory_region **regions,
218 					 unsigned int num_regions)
219 {
220 	struct drm_i915_gem_object *obj, *import_obj;
221 	struct drm_gem_object *import;
222 	struct dma_buf *dmabuf;
223 	struct dma_buf_attachment *import_attach;
224 	struct sg_table *st;
225 	long timeout;
226 	int err;
227 
228 	force_different_devices = true;
229 
230 	obj = __i915_gem_object_create_user(i915, SZ_8M,
231 					    regions, num_regions);
232 	if (IS_ERR(obj)) {
233 		pr_err("__i915_gem_object_create_user failed with err=%ld\n",
234 		       PTR_ERR(obj));
235 		err = PTR_ERR(obj);
236 		goto out_ret;
237 	}
238 
239 	dmabuf = i915_gem_prime_export(&obj->base, 0);
240 	if (IS_ERR(dmabuf)) {
241 		pr_err("i915_gem_prime_export failed with err=%ld\n",
242 		       PTR_ERR(dmabuf));
243 		err = PTR_ERR(dmabuf);
244 		goto out;
245 	}
246 
247 	import = i915_gem_prime_import(&i915->drm, dmabuf);
248 	if (IS_ERR(import)) {
249 		pr_err("i915_gem_prime_import failed with err=%ld\n",
250 		       PTR_ERR(import));
251 		err = PTR_ERR(import);
252 		goto out_dmabuf;
253 	}
254 	import_obj = to_intel_bo(import);
255 
256 	if (import == &obj->base) {
257 		pr_err("i915_gem_prime_import reused gem object!\n");
258 		err = -EINVAL;
259 		goto out_import;
260 	}
261 
262 	i915_gem_object_lock(import_obj, NULL);
263 	err = __i915_gem_object_get_pages(import_obj);
264 	if (err) {
265 		pr_err("Different objects dma-buf get_pages failed!\n");
266 		i915_gem_object_unlock(import_obj);
267 		goto out_import;
268 	}
269 
270 	/*
271 	 * If the exported object is not in system memory, something
272 	 * weird is going on. TODO: When p2p is supported, this is no
273 	 * longer considered weird.
274 	 */
275 	if (obj->mm.region != i915->mm.regions[INTEL_REGION_SMEM]) {
276 		pr_err("Exported dma-buf is not in system memory\n");
277 		err = -EINVAL;
278 	}
279 
280 	i915_gem_object_unlock(import_obj);
281 
282 	err = verify_access(i915, obj, import_obj);
283 	if (err)
284 		goto out_import;
285 
286 	/* Now try a fake an importer */
287 	import_attach = dma_buf_attach(dmabuf, obj->base.dev->dev);
288 	if (IS_ERR(import_attach)) {
289 		err = PTR_ERR(import_attach);
290 		goto out_import;
291 	}
292 
293 	st = dma_buf_map_attachment_unlocked(import_attach, DMA_BIDIRECTIONAL);
294 	if (IS_ERR(st)) {
295 		err = PTR_ERR(st);
296 		goto out_detach;
297 	}
298 
299 	timeout = dma_resv_wait_timeout(dmabuf->resv, DMA_RESV_USAGE_WRITE,
300 					true, 5 * HZ);
301 	if (!timeout) {
302 		pr_err("dmabuf wait for exclusive fence timed out.\n");
303 		timeout = -ETIME;
304 	}
305 	err = timeout > 0 ? 0 : timeout;
306 	dma_buf_unmap_attachment_unlocked(import_attach, st, DMA_BIDIRECTIONAL);
307 out_detach:
308 	dma_buf_detach(dmabuf, import_attach);
309 out_import:
310 	i915_gem_object_put(import_obj);
311 out_dmabuf:
312 	dma_buf_put(dmabuf);
313 out:
314 	i915_gem_object_put(obj);
315 out_ret:
316 	force_different_devices = false;
317 	return err;
318 }
319 
320 static int igt_dmabuf_import_same_driver_smem(void *arg)
321 {
322 	struct drm_i915_private *i915 = arg;
323 	struct intel_memory_region *smem = i915->mm.regions[INTEL_REGION_SMEM];
324 
325 	return igt_dmabuf_import_same_driver(i915, &smem, 1);
326 }
327 
328 static int igt_dmabuf_import_same_driver_lmem_smem(void *arg)
329 {
330 	struct drm_i915_private *i915 = arg;
331 	struct intel_memory_region *regions[2];
332 
333 	if (!i915->mm.regions[INTEL_REGION_LMEM_0])
334 		return 0;
335 
336 	regions[0] = i915->mm.regions[INTEL_REGION_LMEM_0];
337 	regions[1] = i915->mm.regions[INTEL_REGION_SMEM];
338 	return igt_dmabuf_import_same_driver(i915, regions, 2);
339 }
340 
341 static int igt_dmabuf_import(void *arg)
342 {
343 	struct drm_i915_private *i915 = arg;
344 	struct drm_i915_gem_object *obj;
345 	struct dma_buf *dmabuf;
346 	void *obj_map, *dma_map;
347 	struct iosys_map map;
348 	u32 pattern[] = { 0, 0xaa, 0xcc, 0x55, 0xff };
349 	int err, i;
350 
351 	dmabuf = mock_dmabuf(1);
352 	if (IS_ERR(dmabuf))
353 		return PTR_ERR(dmabuf);
354 
355 	obj = to_intel_bo(i915_gem_prime_import(&i915->drm, dmabuf));
356 	if (IS_ERR(obj)) {
357 		pr_err("i915_gem_prime_import failed with err=%d\n",
358 		       (int)PTR_ERR(obj));
359 		err = PTR_ERR(obj);
360 		goto out_dmabuf;
361 	}
362 
363 	if (obj->base.dev != &i915->drm) {
364 		pr_err("i915_gem_prime_import created a non-i915 object!\n");
365 		err = -EINVAL;
366 		goto out_obj;
367 	}
368 
369 	if (obj->base.size != PAGE_SIZE) {
370 		pr_err("i915_gem_prime_import is wrong size found %lld, expected %ld\n",
371 		       (long long)obj->base.size, PAGE_SIZE);
372 		err = -EINVAL;
373 		goto out_obj;
374 	}
375 
376 	err = dma_buf_vmap_unlocked(dmabuf, &map);
377 	dma_map = err ? NULL : map.vaddr;
378 	if (!dma_map) {
379 		pr_err("dma_buf_vmap failed\n");
380 		err = -ENOMEM;
381 		goto out_obj;
382 	}
383 
384 	if (0) { /* Can not yet map dmabuf */
385 		obj_map = i915_gem_object_pin_map(obj, I915_MAP_WB);
386 		if (IS_ERR(obj_map)) {
387 			err = PTR_ERR(obj_map);
388 			pr_err("i915_gem_object_pin_map failed with err=%d\n", err);
389 			goto out_dma_map;
390 		}
391 
392 		for (i = 0; i < ARRAY_SIZE(pattern); i++) {
393 			memset(dma_map, pattern[i], PAGE_SIZE);
394 			if (memchr_inv(obj_map, pattern[i], PAGE_SIZE)) {
395 				err = -EINVAL;
396 				pr_err("imported vmap not all set to %x!\n", pattern[i]);
397 				i915_gem_object_unpin_map(obj);
398 				goto out_dma_map;
399 			}
400 		}
401 
402 		for (i = 0; i < ARRAY_SIZE(pattern); i++) {
403 			memset(obj_map, pattern[i], PAGE_SIZE);
404 			if (memchr_inv(dma_map, pattern[i], PAGE_SIZE)) {
405 				err = -EINVAL;
406 				pr_err("exported vmap not all set to %x!\n", pattern[i]);
407 				i915_gem_object_unpin_map(obj);
408 				goto out_dma_map;
409 			}
410 		}
411 
412 		i915_gem_object_unpin_map(obj);
413 	}
414 
415 	err = 0;
416 out_dma_map:
417 	dma_buf_vunmap_unlocked(dmabuf, &map);
418 out_obj:
419 	i915_gem_object_put(obj);
420 out_dmabuf:
421 	dma_buf_put(dmabuf);
422 	return err;
423 }
424 
425 static int igt_dmabuf_import_ownership(void *arg)
426 {
427 	struct drm_i915_private *i915 = arg;
428 	struct drm_i915_gem_object *obj;
429 	struct dma_buf *dmabuf;
430 	struct iosys_map map;
431 	void *ptr;
432 	int err;
433 
434 	dmabuf = mock_dmabuf(1);
435 	if (IS_ERR(dmabuf))
436 		return PTR_ERR(dmabuf);
437 
438 	err = dma_buf_vmap_unlocked(dmabuf, &map);
439 	ptr = err ? NULL : map.vaddr;
440 	if (!ptr) {
441 		pr_err("dma_buf_vmap failed\n");
442 		err = -ENOMEM;
443 		goto err_dmabuf;
444 	}
445 
446 	memset(ptr, 0xc5, PAGE_SIZE);
447 	dma_buf_vunmap_unlocked(dmabuf, &map);
448 
449 	obj = to_intel_bo(i915_gem_prime_import(&i915->drm, dmabuf));
450 	if (IS_ERR(obj)) {
451 		pr_err("i915_gem_prime_import failed with err=%d\n",
452 		       (int)PTR_ERR(obj));
453 		err = PTR_ERR(obj);
454 		goto err_dmabuf;
455 	}
456 
457 	dma_buf_put(dmabuf);
458 
459 	err = i915_gem_object_pin_pages_unlocked(obj);
460 	if (err) {
461 		pr_err("i915_gem_object_pin_pages failed with err=%d\n", err);
462 		goto out_obj;
463 	}
464 
465 	err = 0;
466 	i915_gem_object_unpin_pages(obj);
467 out_obj:
468 	i915_gem_object_put(obj);
469 	return err;
470 
471 err_dmabuf:
472 	dma_buf_put(dmabuf);
473 	return err;
474 }
475 
476 static int igt_dmabuf_export_vmap(void *arg)
477 {
478 	struct drm_i915_private *i915 = arg;
479 	struct drm_i915_gem_object *obj;
480 	struct dma_buf *dmabuf;
481 	struct iosys_map map;
482 	void *ptr;
483 	int err;
484 
485 	obj = i915_gem_object_create_shmem(i915, PAGE_SIZE);
486 	if (IS_ERR(obj))
487 		return PTR_ERR(obj);
488 
489 	dmabuf = i915_gem_prime_export(&obj->base, 0);
490 	if (IS_ERR(dmabuf)) {
491 		pr_err("i915_gem_prime_export failed with err=%d\n",
492 		       (int)PTR_ERR(dmabuf));
493 		err = PTR_ERR(dmabuf);
494 		goto err_obj;
495 	}
496 	i915_gem_object_put(obj);
497 
498 	err = dma_buf_vmap_unlocked(dmabuf, &map);
499 	ptr = err ? NULL : map.vaddr;
500 	if (!ptr) {
501 		pr_err("dma_buf_vmap failed\n");
502 		err = -ENOMEM;
503 		goto out;
504 	}
505 
506 	if (memchr_inv(ptr, 0, dmabuf->size)) {
507 		pr_err("Exported object not initialiased to zero!\n");
508 		err = -EINVAL;
509 		goto out;
510 	}
511 
512 	memset(ptr, 0xc5, dmabuf->size);
513 
514 	err = 0;
515 	dma_buf_vunmap_unlocked(dmabuf, &map);
516 out:
517 	dma_buf_put(dmabuf);
518 	return err;
519 
520 err_obj:
521 	i915_gem_object_put(obj);
522 	return err;
523 }
524 
525 int i915_gem_dmabuf_mock_selftests(void)
526 {
527 	static const struct i915_subtest tests[] = {
528 		SUBTEST(igt_dmabuf_export),
529 		SUBTEST(igt_dmabuf_import_self),
530 		SUBTEST(igt_dmabuf_import),
531 		SUBTEST(igt_dmabuf_import_ownership),
532 		SUBTEST(igt_dmabuf_export_vmap),
533 	};
534 	struct drm_i915_private *i915;
535 	int err;
536 
537 	i915 = mock_gem_device();
538 	if (!i915)
539 		return -ENOMEM;
540 
541 	err = i915_subtests(tests, i915);
542 
543 	mock_destroy_device(i915);
544 	return err;
545 }
546 
547 int i915_gem_dmabuf_live_selftests(struct drm_i915_private *i915)
548 {
549 	static const struct i915_subtest tests[] = {
550 		SUBTEST(igt_dmabuf_export),
551 		SUBTEST(igt_dmabuf_import_same_driver_lmem),
552 		SUBTEST(igt_dmabuf_import_same_driver_smem),
553 		SUBTEST(igt_dmabuf_import_same_driver_lmem_smem),
554 	};
555 
556 	return i915_live_subtests(tests, i915);
557 }
558