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