110be98a7SChris Wilson /*
210be98a7SChris Wilson  * SPDX-License-Identifier: MIT
310be98a7SChris Wilson  *
410be98a7SChris Wilson  * Copyright © 2016 Intel Corporation
510be98a7SChris Wilson  */
610be98a7SChris Wilson 
737d63f8fSChris Wilson #include "i915_drv.h"
810be98a7SChris Wilson #include "i915_selftest.h"
910be98a7SChris Wilson 
1010be98a7SChris Wilson #include "mock_dmabuf.h"
1110be98a7SChris Wilson #include "selftests/mock_gem_device.h"
1210be98a7SChris Wilson 
1310be98a7SChris Wilson static int igt_dmabuf_export(void *arg)
1410be98a7SChris Wilson {
1510be98a7SChris Wilson 	struct drm_i915_private *i915 = arg;
1610be98a7SChris Wilson 	struct drm_i915_gem_object *obj;
1710be98a7SChris Wilson 	struct dma_buf *dmabuf;
1810be98a7SChris Wilson 
1910be98a7SChris Wilson 	obj = i915_gem_object_create_shmem(i915, PAGE_SIZE);
2010be98a7SChris Wilson 	if (IS_ERR(obj))
2110be98a7SChris Wilson 		return PTR_ERR(obj);
2210be98a7SChris Wilson 
23d8080976SDaniel Vetter 	dmabuf = i915_gem_prime_export(&obj->base, 0);
2410be98a7SChris Wilson 	i915_gem_object_put(obj);
2510be98a7SChris Wilson 	if (IS_ERR(dmabuf)) {
2610be98a7SChris Wilson 		pr_err("i915_gem_prime_export failed with err=%d\n",
2710be98a7SChris Wilson 		       (int)PTR_ERR(dmabuf));
2810be98a7SChris Wilson 		return PTR_ERR(dmabuf);
2910be98a7SChris Wilson 	}
3010be98a7SChris Wilson 
3110be98a7SChris Wilson 	dma_buf_put(dmabuf);
3210be98a7SChris Wilson 	return 0;
3310be98a7SChris Wilson }
3410be98a7SChris Wilson 
3510be98a7SChris Wilson static int igt_dmabuf_import_self(void *arg)
3610be98a7SChris Wilson {
3710be98a7SChris Wilson 	struct drm_i915_private *i915 = arg;
3810be98a7SChris Wilson 	struct drm_i915_gem_object *obj;
3910be98a7SChris Wilson 	struct drm_gem_object *import;
4010be98a7SChris Wilson 	struct dma_buf *dmabuf;
4110be98a7SChris Wilson 	int err;
4210be98a7SChris Wilson 
4310be98a7SChris Wilson 	obj = i915_gem_object_create_shmem(i915, PAGE_SIZE);
4410be98a7SChris Wilson 	if (IS_ERR(obj))
4510be98a7SChris Wilson 		return PTR_ERR(obj);
4610be98a7SChris Wilson 
47d8080976SDaniel Vetter 	dmabuf = i915_gem_prime_export(&obj->base, 0);
4810be98a7SChris Wilson 	if (IS_ERR(dmabuf)) {
4910be98a7SChris Wilson 		pr_err("i915_gem_prime_export failed with err=%d\n",
5010be98a7SChris Wilson 		       (int)PTR_ERR(dmabuf));
5110be98a7SChris Wilson 		err = PTR_ERR(dmabuf);
5210be98a7SChris Wilson 		goto out;
5310be98a7SChris Wilson 	}
5410be98a7SChris Wilson 
5510be98a7SChris Wilson 	import = i915_gem_prime_import(&i915->drm, dmabuf);
5610be98a7SChris Wilson 	if (IS_ERR(import)) {
5710be98a7SChris Wilson 		pr_err("i915_gem_prime_import failed with err=%d\n",
5810be98a7SChris Wilson 		       (int)PTR_ERR(import));
5910be98a7SChris Wilson 		err = PTR_ERR(import);
6010be98a7SChris Wilson 		goto out_dmabuf;
6110be98a7SChris Wilson 	}
6210be98a7SChris Wilson 
6310be98a7SChris Wilson 	if (import != &obj->base) {
6410be98a7SChris Wilson 		pr_err("i915_gem_prime_import created a new object!\n");
6510be98a7SChris Wilson 		err = -EINVAL;
6610be98a7SChris Wilson 		goto out_import;
6710be98a7SChris Wilson 	}
6810be98a7SChris Wilson 
6910be98a7SChris Wilson 	err = 0;
7010be98a7SChris Wilson out_import:
7110be98a7SChris Wilson 	i915_gem_object_put(to_intel_bo(import));
7210be98a7SChris Wilson out_dmabuf:
7310be98a7SChris Wilson 	dma_buf_put(dmabuf);
7410be98a7SChris Wilson out:
7510be98a7SChris Wilson 	i915_gem_object_put(obj);
7610be98a7SChris Wilson 	return err;
7710be98a7SChris Wilson }
7810be98a7SChris Wilson 
7910be98a7SChris Wilson static int igt_dmabuf_import(void *arg)
8010be98a7SChris Wilson {
8110be98a7SChris Wilson 	struct drm_i915_private *i915 = arg;
8210be98a7SChris Wilson 	struct drm_i915_gem_object *obj;
8310be98a7SChris Wilson 	struct dma_buf *dmabuf;
8410be98a7SChris Wilson 	void *obj_map, *dma_map;
85*6619ccf1SThomas Zimmermann 	struct dma_buf_map map;
8610be98a7SChris Wilson 	u32 pattern[] = { 0, 0xaa, 0xcc, 0x55, 0xff };
8710be98a7SChris Wilson 	int err, i;
8810be98a7SChris Wilson 
8910be98a7SChris Wilson 	dmabuf = mock_dmabuf(1);
9010be98a7SChris Wilson 	if (IS_ERR(dmabuf))
9110be98a7SChris Wilson 		return PTR_ERR(dmabuf);
9210be98a7SChris Wilson 
9310be98a7SChris Wilson 	obj = to_intel_bo(i915_gem_prime_import(&i915->drm, dmabuf));
9410be98a7SChris Wilson 	if (IS_ERR(obj)) {
9510be98a7SChris Wilson 		pr_err("i915_gem_prime_import failed with err=%d\n",
9610be98a7SChris Wilson 		       (int)PTR_ERR(obj));
9710be98a7SChris Wilson 		err = PTR_ERR(obj);
9810be98a7SChris Wilson 		goto out_dmabuf;
9910be98a7SChris Wilson 	}
10010be98a7SChris Wilson 
10110be98a7SChris Wilson 	if (obj->base.dev != &i915->drm) {
10210be98a7SChris Wilson 		pr_err("i915_gem_prime_import created a non-i915 object!\n");
10310be98a7SChris Wilson 		err = -EINVAL;
10410be98a7SChris Wilson 		goto out_obj;
10510be98a7SChris Wilson 	}
10610be98a7SChris Wilson 
10710be98a7SChris Wilson 	if (obj->base.size != PAGE_SIZE) {
10810be98a7SChris Wilson 		pr_err("i915_gem_prime_import is wrong size found %lld, expected %ld\n",
10910be98a7SChris Wilson 		       (long long)obj->base.size, PAGE_SIZE);
11010be98a7SChris Wilson 		err = -EINVAL;
11110be98a7SChris Wilson 		goto out_obj;
11210be98a7SChris Wilson 	}
11310be98a7SChris Wilson 
114*6619ccf1SThomas Zimmermann 	err = dma_buf_vmap(dmabuf, &map);
115*6619ccf1SThomas Zimmermann 	dma_map = err ? NULL : map.vaddr;
11610be98a7SChris Wilson 	if (!dma_map) {
11710be98a7SChris Wilson 		pr_err("dma_buf_vmap failed\n");
11810be98a7SChris Wilson 		err = -ENOMEM;
11910be98a7SChris Wilson 		goto out_obj;
12010be98a7SChris Wilson 	}
12110be98a7SChris Wilson 
12210be98a7SChris Wilson 	if (0) { /* Can not yet map dmabuf */
12310be98a7SChris Wilson 		obj_map = i915_gem_object_pin_map(obj, I915_MAP_WB);
12410be98a7SChris Wilson 		if (IS_ERR(obj_map)) {
12510be98a7SChris Wilson 			err = PTR_ERR(obj_map);
12610be98a7SChris Wilson 			pr_err("i915_gem_object_pin_map failed with err=%d\n", err);
12710be98a7SChris Wilson 			goto out_dma_map;
12810be98a7SChris Wilson 		}
12910be98a7SChris Wilson 
13010be98a7SChris Wilson 		for (i = 0; i < ARRAY_SIZE(pattern); i++) {
13110be98a7SChris Wilson 			memset(dma_map, pattern[i], PAGE_SIZE);
13210be98a7SChris Wilson 			if (memchr_inv(obj_map, pattern[i], PAGE_SIZE)) {
13310be98a7SChris Wilson 				err = -EINVAL;
13410be98a7SChris Wilson 				pr_err("imported vmap not all set to %x!\n", pattern[i]);
13510be98a7SChris Wilson 				i915_gem_object_unpin_map(obj);
13610be98a7SChris Wilson 				goto out_dma_map;
13710be98a7SChris Wilson 			}
13810be98a7SChris Wilson 		}
13910be98a7SChris Wilson 
14010be98a7SChris Wilson 		for (i = 0; i < ARRAY_SIZE(pattern); i++) {
14110be98a7SChris Wilson 			memset(obj_map, pattern[i], PAGE_SIZE);
14210be98a7SChris Wilson 			if (memchr_inv(dma_map, pattern[i], PAGE_SIZE)) {
14310be98a7SChris Wilson 				err = -EINVAL;
14410be98a7SChris Wilson 				pr_err("exported vmap not all set to %x!\n", pattern[i]);
14510be98a7SChris Wilson 				i915_gem_object_unpin_map(obj);
14610be98a7SChris Wilson 				goto out_dma_map;
14710be98a7SChris Wilson 			}
14810be98a7SChris Wilson 		}
14910be98a7SChris Wilson 
15010be98a7SChris Wilson 		i915_gem_object_unpin_map(obj);
15110be98a7SChris Wilson 	}
15210be98a7SChris Wilson 
15310be98a7SChris Wilson 	err = 0;
15410be98a7SChris Wilson out_dma_map:
15510be98a7SChris Wilson 	dma_buf_vunmap(dmabuf, dma_map);
15610be98a7SChris Wilson out_obj:
15710be98a7SChris Wilson 	i915_gem_object_put(obj);
15810be98a7SChris Wilson out_dmabuf:
15910be98a7SChris Wilson 	dma_buf_put(dmabuf);
16010be98a7SChris Wilson 	return err;
16110be98a7SChris Wilson }
16210be98a7SChris Wilson 
16310be98a7SChris Wilson static int igt_dmabuf_import_ownership(void *arg)
16410be98a7SChris Wilson {
16510be98a7SChris Wilson 	struct drm_i915_private *i915 = arg;
16610be98a7SChris Wilson 	struct drm_i915_gem_object *obj;
16710be98a7SChris Wilson 	struct dma_buf *dmabuf;
168*6619ccf1SThomas Zimmermann 	struct dma_buf_map map;
16910be98a7SChris Wilson 	void *ptr;
17010be98a7SChris Wilson 	int err;
17110be98a7SChris Wilson 
17210be98a7SChris Wilson 	dmabuf = mock_dmabuf(1);
17310be98a7SChris Wilson 	if (IS_ERR(dmabuf))
17410be98a7SChris Wilson 		return PTR_ERR(dmabuf);
17510be98a7SChris Wilson 
176*6619ccf1SThomas Zimmermann 	err = dma_buf_vmap(dmabuf, &map);
177*6619ccf1SThomas Zimmermann 	ptr = err ? NULL : map.vaddr;
17810be98a7SChris Wilson 	if (!ptr) {
17910be98a7SChris Wilson 		pr_err("dma_buf_vmap failed\n");
18010be98a7SChris Wilson 		err = -ENOMEM;
18110be98a7SChris Wilson 		goto err_dmabuf;
18210be98a7SChris Wilson 	}
18310be98a7SChris Wilson 
18410be98a7SChris Wilson 	memset(ptr, 0xc5, PAGE_SIZE);
18510be98a7SChris Wilson 	dma_buf_vunmap(dmabuf, ptr);
18610be98a7SChris Wilson 
18710be98a7SChris Wilson 	obj = to_intel_bo(i915_gem_prime_import(&i915->drm, dmabuf));
18810be98a7SChris Wilson 	if (IS_ERR(obj)) {
18910be98a7SChris Wilson 		pr_err("i915_gem_prime_import failed with err=%d\n",
19010be98a7SChris Wilson 		       (int)PTR_ERR(obj));
19110be98a7SChris Wilson 		err = PTR_ERR(obj);
19210be98a7SChris Wilson 		goto err_dmabuf;
19310be98a7SChris Wilson 	}
19410be98a7SChris Wilson 
19510be98a7SChris Wilson 	dma_buf_put(dmabuf);
19610be98a7SChris Wilson 
19710be98a7SChris Wilson 	err = i915_gem_object_pin_pages(obj);
19810be98a7SChris Wilson 	if (err) {
19910be98a7SChris Wilson 		pr_err("i915_gem_object_pin_pages failed with err=%d\n", err);
20010be98a7SChris Wilson 		goto out_obj;
20110be98a7SChris Wilson 	}
20210be98a7SChris Wilson 
20310be98a7SChris Wilson 	err = 0;
20410be98a7SChris Wilson 	i915_gem_object_unpin_pages(obj);
20510be98a7SChris Wilson out_obj:
20610be98a7SChris Wilson 	i915_gem_object_put(obj);
20710be98a7SChris Wilson 	return err;
20810be98a7SChris Wilson 
20910be98a7SChris Wilson err_dmabuf:
21010be98a7SChris Wilson 	dma_buf_put(dmabuf);
21110be98a7SChris Wilson 	return err;
21210be98a7SChris Wilson }
21310be98a7SChris Wilson 
21410be98a7SChris Wilson static int igt_dmabuf_export_vmap(void *arg)
21510be98a7SChris Wilson {
21610be98a7SChris Wilson 	struct drm_i915_private *i915 = arg;
21710be98a7SChris Wilson 	struct drm_i915_gem_object *obj;
21810be98a7SChris Wilson 	struct dma_buf *dmabuf;
219*6619ccf1SThomas Zimmermann 	struct dma_buf_map map;
22010be98a7SChris Wilson 	void *ptr;
22110be98a7SChris Wilson 	int err;
22210be98a7SChris Wilson 
22310be98a7SChris Wilson 	obj = i915_gem_object_create_shmem(i915, PAGE_SIZE);
22410be98a7SChris Wilson 	if (IS_ERR(obj))
22510be98a7SChris Wilson 		return PTR_ERR(obj);
22610be98a7SChris Wilson 
227d8080976SDaniel Vetter 	dmabuf = i915_gem_prime_export(&obj->base, 0);
22810be98a7SChris Wilson 	if (IS_ERR(dmabuf)) {
22910be98a7SChris Wilson 		pr_err("i915_gem_prime_export failed with err=%d\n",
23010be98a7SChris Wilson 		       (int)PTR_ERR(dmabuf));
23110be98a7SChris Wilson 		err = PTR_ERR(dmabuf);
23210be98a7SChris Wilson 		goto err_obj;
23310be98a7SChris Wilson 	}
23410be98a7SChris Wilson 	i915_gem_object_put(obj);
23510be98a7SChris Wilson 
236*6619ccf1SThomas Zimmermann 	err = dma_buf_vmap(dmabuf, &map);
237*6619ccf1SThomas Zimmermann 	ptr = err ? NULL : map.vaddr;
23810be98a7SChris Wilson 	if (!ptr) {
23910be98a7SChris Wilson 		pr_err("dma_buf_vmap failed\n");
24010be98a7SChris Wilson 		err = -ENOMEM;
24110be98a7SChris Wilson 		goto out;
24210be98a7SChris Wilson 	}
24310be98a7SChris Wilson 
24410be98a7SChris Wilson 	if (memchr_inv(ptr, 0, dmabuf->size)) {
24510be98a7SChris Wilson 		pr_err("Exported object not initialiased to zero!\n");
24610be98a7SChris Wilson 		err = -EINVAL;
24710be98a7SChris Wilson 		goto out;
24810be98a7SChris Wilson 	}
24910be98a7SChris Wilson 
25010be98a7SChris Wilson 	memset(ptr, 0xc5, dmabuf->size);
25110be98a7SChris Wilson 
25210be98a7SChris Wilson 	err = 0;
25310be98a7SChris Wilson 	dma_buf_vunmap(dmabuf, ptr);
25410be98a7SChris Wilson out:
25510be98a7SChris Wilson 	dma_buf_put(dmabuf);
25610be98a7SChris Wilson 	return err;
25710be98a7SChris Wilson 
25810be98a7SChris Wilson err_obj:
25910be98a7SChris Wilson 	i915_gem_object_put(obj);
26010be98a7SChris Wilson 	return err;
26110be98a7SChris Wilson }
26210be98a7SChris Wilson 
26310be98a7SChris Wilson int i915_gem_dmabuf_mock_selftests(void)
26410be98a7SChris Wilson {
26510be98a7SChris Wilson 	static const struct i915_subtest tests[] = {
26610be98a7SChris Wilson 		SUBTEST(igt_dmabuf_export),
26710be98a7SChris Wilson 		SUBTEST(igt_dmabuf_import_self),
26810be98a7SChris Wilson 		SUBTEST(igt_dmabuf_import),
26910be98a7SChris Wilson 		SUBTEST(igt_dmabuf_import_ownership),
27010be98a7SChris Wilson 		SUBTEST(igt_dmabuf_export_vmap),
27110be98a7SChris Wilson 	};
27210be98a7SChris Wilson 	struct drm_i915_private *i915;
27310be98a7SChris Wilson 	int err;
27410be98a7SChris Wilson 
27510be98a7SChris Wilson 	i915 = mock_gem_device();
27610be98a7SChris Wilson 	if (!i915)
27710be98a7SChris Wilson 		return -ENOMEM;
27810be98a7SChris Wilson 
27910be98a7SChris Wilson 	err = i915_subtests(tests, i915);
28010be98a7SChris Wilson 
28182be0d75SDaniel Vetter 	mock_destroy_device(i915);
28210be98a7SChris Wilson 	return err;
28310be98a7SChris Wilson }
28410be98a7SChris Wilson 
28510be98a7SChris Wilson int i915_gem_dmabuf_live_selftests(struct drm_i915_private *i915)
28610be98a7SChris Wilson {
28710be98a7SChris Wilson 	static const struct i915_subtest tests[] = {
28810be98a7SChris Wilson 		SUBTEST(igt_dmabuf_export),
28910be98a7SChris Wilson 	};
29010be98a7SChris Wilson 
29110be98a7SChris Wilson 	return i915_subtests(tests, i915);
29210be98a7SChris Wilson }
293