xref: /openbmc/linux/drivers/dma-buf/st-dma-resv.c (revision 7bc80a54)
11d51775cSChristian König /* SPDX-License-Identifier: MIT */
21d51775cSChristian König 
31d51775cSChristian König /*
41d51775cSChristian König * Copyright © 2019 Intel Corporation
51d51775cSChristian König * Copyright © 2021 Advanced Micro Devices, Inc.
61d51775cSChristian König */
71d51775cSChristian König 
81d51775cSChristian König #include <linux/slab.h>
91d51775cSChristian König #include <linux/spinlock.h>
101d51775cSChristian König #include <linux/dma-resv.h>
111d51775cSChristian König 
121d51775cSChristian König #include "selftest.h"
131d51775cSChristian König 
141d51775cSChristian König static struct spinlock fence_lock;
151d51775cSChristian König 
161d51775cSChristian König static const char *fence_name(struct dma_fence *f)
171d51775cSChristian König {
181d51775cSChristian König 	return "selftest";
191d51775cSChristian König }
201d51775cSChristian König 
211d51775cSChristian König static const struct dma_fence_ops fence_ops = {
221d51775cSChristian König 	.get_driver_name = fence_name,
231d51775cSChristian König 	.get_timeline_name = fence_name,
241d51775cSChristian König };
251d51775cSChristian König 
261d51775cSChristian König static struct dma_fence *alloc_fence(void)
271d51775cSChristian König {
281d51775cSChristian König 	struct dma_fence *f;
291d51775cSChristian König 
301d51775cSChristian König 	f = kmalloc(sizeof(*f), GFP_KERNEL);
311d51775cSChristian König 	if (!f)
321d51775cSChristian König 		return NULL;
331d51775cSChristian König 
341d51775cSChristian König 	dma_fence_init(f, &fence_ops, &fence_lock, 0, 0);
351d51775cSChristian König 	return f;
361d51775cSChristian König }
371d51775cSChristian König 
381d51775cSChristian König static int sanitycheck(void *arg)
391d51775cSChristian König {
401d51775cSChristian König 	struct dma_resv resv;
411d51775cSChristian König 	struct dma_fence *f;
421d51775cSChristian König 	int r;
431d51775cSChristian König 
441d51775cSChristian König 	f = alloc_fence();
451d51775cSChristian König 	if (!f)
461d51775cSChristian König 		return -ENOMEM;
471d51775cSChristian König 
481d51775cSChristian König 	dma_fence_signal(f);
491d51775cSChristian König 	dma_fence_put(f);
501d51775cSChristian König 
511d51775cSChristian König 	dma_resv_init(&resv);
521d51775cSChristian König 	r = dma_resv_lock(&resv, NULL);
531d51775cSChristian König 	if (r)
541d51775cSChristian König 		pr_err("Resv locking failed\n");
551d51775cSChristian König 	else
561d51775cSChristian König 		dma_resv_unlock(&resv);
571d51775cSChristian König 	dma_resv_fini(&resv);
581d51775cSChristian König 	return r;
591d51775cSChristian König }
601d51775cSChristian König 
61*7bc80a54SChristian König static int test_signaling(void *arg, enum dma_resv_usage usage)
621d51775cSChristian König {
631d51775cSChristian König 	struct dma_resv resv;
641d51775cSChristian König 	struct dma_fence *f;
651d51775cSChristian König 	int r;
661d51775cSChristian König 
671d51775cSChristian König 	f = alloc_fence();
681d51775cSChristian König 	if (!f)
691d51775cSChristian König 		return -ENOMEM;
701d51775cSChristian König 
711d51775cSChristian König 	dma_resv_init(&resv);
721d51775cSChristian König 	r = dma_resv_lock(&resv, NULL);
731d51775cSChristian König 	if (r) {
741d51775cSChristian König 		pr_err("Resv locking failed\n");
751d51775cSChristian König 		goto err_free;
761d51775cSChristian König 	}
771d51775cSChristian König 
78c8d4c18bSChristian König 	r = dma_resv_reserve_fences(&resv, 1);
791d51775cSChristian König 	if (r) {
801d51775cSChristian König 		pr_err("Resv shared slot allocation failed\n");
811d51775cSChristian König 		goto err_unlock;
821d51775cSChristian König 	}
831d51775cSChristian König 
84*7bc80a54SChristian König 	if (usage >= DMA_RESV_USAGE_READ)
851d51775cSChristian König 		dma_resv_add_shared_fence(&resv, f);
86c8d4c18bSChristian König 	else
871d51775cSChristian König 		dma_resv_add_excl_fence(&resv, f);
881d51775cSChristian König 
89*7bc80a54SChristian König 	if (dma_resv_test_signaled(&resv, usage)) {
901d51775cSChristian König 		pr_err("Resv unexpectedly signaled\n");
911d51775cSChristian König 		r = -EINVAL;
921d51775cSChristian König 		goto err_unlock;
931d51775cSChristian König 	}
941d51775cSChristian König 	dma_fence_signal(f);
95*7bc80a54SChristian König 	if (!dma_resv_test_signaled(&resv, usage)) {
961d51775cSChristian König 		pr_err("Resv not reporting signaled\n");
971d51775cSChristian König 		r = -EINVAL;
981d51775cSChristian König 		goto err_unlock;
991d51775cSChristian König 	}
1001d51775cSChristian König err_unlock:
1011d51775cSChristian König 	dma_resv_unlock(&resv);
1021d51775cSChristian König err_free:
1031d51775cSChristian König 	dma_resv_fini(&resv);
1041d51775cSChristian König 	dma_fence_put(f);
1051d51775cSChristian König 	return r;
1061d51775cSChristian König }
1071d51775cSChristian König 
1081d51775cSChristian König static int test_excl_signaling(void *arg)
1091d51775cSChristian König {
110*7bc80a54SChristian König 	return test_signaling(arg, DMA_RESV_USAGE_WRITE);
1111d51775cSChristian König }
1121d51775cSChristian König 
1131d51775cSChristian König static int test_shared_signaling(void *arg)
1141d51775cSChristian König {
115*7bc80a54SChristian König 	return test_signaling(arg, DMA_RESV_USAGE_READ);
1161d51775cSChristian König }
1171d51775cSChristian König 
118*7bc80a54SChristian König static int test_for_each(void *arg, enum dma_resv_usage usage)
1191d51775cSChristian König {
1201d51775cSChristian König 	struct dma_resv_iter cursor;
1211d51775cSChristian König 	struct dma_fence *f, *fence;
1221d51775cSChristian König 	struct dma_resv resv;
1231d51775cSChristian König 	int r;
1241d51775cSChristian König 
1251d51775cSChristian König 	f = alloc_fence();
1261d51775cSChristian König 	if (!f)
1271d51775cSChristian König 		return -ENOMEM;
1281d51775cSChristian König 
1291d51775cSChristian König 	dma_resv_init(&resv);
1301d51775cSChristian König 	r = dma_resv_lock(&resv, NULL);
1311d51775cSChristian König 	if (r) {
1321d51775cSChristian König 		pr_err("Resv locking failed\n");
1331d51775cSChristian König 		goto err_free;
1341d51775cSChristian König 	}
1351d51775cSChristian König 
136c8d4c18bSChristian König 	r = dma_resv_reserve_fences(&resv, 1);
1371d51775cSChristian König 	if (r) {
1381d51775cSChristian König 		pr_err("Resv shared slot allocation failed\n");
1391d51775cSChristian König 		goto err_unlock;
1401d51775cSChristian König 	}
1411d51775cSChristian König 
142*7bc80a54SChristian König 	if (usage >= DMA_RESV_USAGE_READ)
1431d51775cSChristian König 		dma_resv_add_shared_fence(&resv, f);
144c8d4c18bSChristian König 	else
1451d51775cSChristian König 		dma_resv_add_excl_fence(&resv, f);
1461d51775cSChristian König 
1471d51775cSChristian König 	r = -ENOENT;
148*7bc80a54SChristian König 	dma_resv_for_each_fence(&cursor, &resv, usage, fence) {
1491d51775cSChristian König 		if (!r) {
1501d51775cSChristian König 			pr_err("More than one fence found\n");
1511d51775cSChristian König 			r = -EINVAL;
1521d51775cSChristian König 			goto err_unlock;
1531d51775cSChristian König 		}
1541d51775cSChristian König 		if (f != fence) {
1551d51775cSChristian König 			pr_err("Unexpected fence\n");
1561d51775cSChristian König 			r = -EINVAL;
1571d51775cSChristian König 			goto err_unlock;
1581d51775cSChristian König 		}
159*7bc80a54SChristian König 		if (dma_resv_iter_is_exclusive(&cursor) !=
160*7bc80a54SChristian König 		    (usage >= DMA_RESV_USAGE_READ)) {
1611d51775cSChristian König 			pr_err("Unexpected fence usage\n");
1621d51775cSChristian König 			r = -EINVAL;
1631d51775cSChristian König 			goto err_unlock;
1641d51775cSChristian König 		}
1651d51775cSChristian König 		r = 0;
1661d51775cSChristian König 	}
1671d51775cSChristian König 	if (r) {
1681d51775cSChristian König 		pr_err("No fence found\n");
1691d51775cSChristian König 		goto err_unlock;
1701d51775cSChristian König 	}
1711d51775cSChristian König 	dma_fence_signal(f);
1721d51775cSChristian König err_unlock:
1731d51775cSChristian König 	dma_resv_unlock(&resv);
1741d51775cSChristian König err_free:
1751d51775cSChristian König 	dma_resv_fini(&resv);
1761d51775cSChristian König 	dma_fence_put(f);
1771d51775cSChristian König 	return r;
1781d51775cSChristian König }
1791d51775cSChristian König 
1801d51775cSChristian König static int test_excl_for_each(void *arg)
1811d51775cSChristian König {
182*7bc80a54SChristian König 	return test_for_each(arg, DMA_RESV_USAGE_WRITE);
1831d51775cSChristian König }
1841d51775cSChristian König 
1851d51775cSChristian König static int test_shared_for_each(void *arg)
1861d51775cSChristian König {
187*7bc80a54SChristian König 	return test_for_each(arg, DMA_RESV_USAGE_READ);
1881d51775cSChristian König }
1891d51775cSChristian König 
190*7bc80a54SChristian König static int test_for_each_unlocked(void *arg, enum dma_resv_usage usage)
1911d51775cSChristian König {
1921d51775cSChristian König 	struct dma_resv_iter cursor;
1931d51775cSChristian König 	struct dma_fence *f, *fence;
1941d51775cSChristian König 	struct dma_resv resv;
1951d51775cSChristian König 	int r;
1961d51775cSChristian König 
1971d51775cSChristian König 	f = alloc_fence();
1981d51775cSChristian König 	if (!f)
1991d51775cSChristian König 		return -ENOMEM;
2001d51775cSChristian König 
2011d51775cSChristian König 	dma_resv_init(&resv);
2021d51775cSChristian König 	r = dma_resv_lock(&resv, NULL);
2031d51775cSChristian König 	if (r) {
2041d51775cSChristian König 		pr_err("Resv locking failed\n");
2051d51775cSChristian König 		goto err_free;
2061d51775cSChristian König 	}
2071d51775cSChristian König 
208c8d4c18bSChristian König 	r = dma_resv_reserve_fences(&resv, 1);
2091d51775cSChristian König 	if (r) {
2101d51775cSChristian König 		pr_err("Resv shared slot allocation failed\n");
2111d51775cSChristian König 		dma_resv_unlock(&resv);
2121d51775cSChristian König 		goto err_free;
2131d51775cSChristian König 	}
2141d51775cSChristian König 
215*7bc80a54SChristian König 	if (usage >= DMA_RESV_USAGE_READ)
2161d51775cSChristian König 		dma_resv_add_shared_fence(&resv, f);
217c8d4c18bSChristian König 	else
2181d51775cSChristian König 		dma_resv_add_excl_fence(&resv, f);
2191d51775cSChristian König 	dma_resv_unlock(&resv);
2201d51775cSChristian König 
2211d51775cSChristian König 	r = -ENOENT;
222*7bc80a54SChristian König 	dma_resv_iter_begin(&cursor, &resv, usage);
2231d51775cSChristian König 	dma_resv_for_each_fence_unlocked(&cursor, fence) {
2241d51775cSChristian König 		if (!r) {
2251d51775cSChristian König 			pr_err("More than one fence found\n");
2261d51775cSChristian König 			r = -EINVAL;
2271d51775cSChristian König 			goto err_iter_end;
2281d51775cSChristian König 		}
2291d51775cSChristian König 		if (!dma_resv_iter_is_restarted(&cursor)) {
2301d51775cSChristian König 			pr_err("No restart flag\n");
2311d51775cSChristian König 			goto err_iter_end;
2321d51775cSChristian König 		}
2331d51775cSChristian König 		if (f != fence) {
2341d51775cSChristian König 			pr_err("Unexpected fence\n");
2351d51775cSChristian König 			r = -EINVAL;
2361d51775cSChristian König 			goto err_iter_end;
2371d51775cSChristian König 		}
238*7bc80a54SChristian König 		if (dma_resv_iter_is_exclusive(&cursor) !=
239*7bc80a54SChristian König 		    (usage >= DMA_RESV_USAGE_READ)) {
2401d51775cSChristian König 			pr_err("Unexpected fence usage\n");
2411d51775cSChristian König 			r = -EINVAL;
2421d51775cSChristian König 			goto err_iter_end;
2431d51775cSChristian König 		}
2441d51775cSChristian König 
2451d51775cSChristian König 		/* We use r as state here */
2461d51775cSChristian König 		if (r == -ENOENT) {
2471d51775cSChristian König 			r = -EINVAL;
2481d51775cSChristian König 			/* That should trigger an restart */
2491d51775cSChristian König 			cursor.seq--;
2501d51775cSChristian König 		} else if (r == -EINVAL) {
2511d51775cSChristian König 			r = 0;
2521d51775cSChristian König 		}
2531d51775cSChristian König 	}
2541d51775cSChristian König 	if (r)
2551d51775cSChristian König 		pr_err("No fence found\n");
2561d51775cSChristian König err_iter_end:
2571d51775cSChristian König 	dma_resv_iter_end(&cursor);
2581d51775cSChristian König 	dma_fence_signal(f);
2591d51775cSChristian König err_free:
2601d51775cSChristian König 	dma_resv_fini(&resv);
2611d51775cSChristian König 	dma_fence_put(f);
2621d51775cSChristian König 	return r;
2631d51775cSChristian König }
2641d51775cSChristian König 
2651d51775cSChristian König static int test_excl_for_each_unlocked(void *arg)
2661d51775cSChristian König {
267*7bc80a54SChristian König 	return test_for_each_unlocked(arg, DMA_RESV_USAGE_WRITE);
2681d51775cSChristian König }
2691d51775cSChristian König 
2701d51775cSChristian König static int test_shared_for_each_unlocked(void *arg)
2711d51775cSChristian König {
272*7bc80a54SChristian König 	return test_for_each_unlocked(arg, DMA_RESV_USAGE_READ);
2731d51775cSChristian König }
2741d51775cSChristian König 
275*7bc80a54SChristian König static int test_get_fences(void *arg, enum dma_resv_usage usage)
2761d51775cSChristian König {
27775ab2b36SChristian König 	struct dma_fence *f, **fences = NULL;
2781d51775cSChristian König 	struct dma_resv resv;
2791d51775cSChristian König 	int r, i;
2801d51775cSChristian König 
2811d51775cSChristian König 	f = alloc_fence();
2821d51775cSChristian König 	if (!f)
2831d51775cSChristian König 		return -ENOMEM;
2841d51775cSChristian König 
2851d51775cSChristian König 	dma_resv_init(&resv);
2861d51775cSChristian König 	r = dma_resv_lock(&resv, NULL);
2871d51775cSChristian König 	if (r) {
2881d51775cSChristian König 		pr_err("Resv locking failed\n");
28955d5e4f9SArnd Bergmann 		goto err_resv;
2901d51775cSChristian König 	}
2911d51775cSChristian König 
292c8d4c18bSChristian König 	r = dma_resv_reserve_fences(&resv, 1);
2931d51775cSChristian König 	if (r) {
2941d51775cSChristian König 		pr_err("Resv shared slot allocation failed\n");
2951d51775cSChristian König 		dma_resv_unlock(&resv);
29655d5e4f9SArnd Bergmann 		goto err_resv;
2971d51775cSChristian König 	}
2981d51775cSChristian König 
299*7bc80a54SChristian König 	if (usage >= DMA_RESV_USAGE_READ)
3001d51775cSChristian König 		dma_resv_add_shared_fence(&resv, f);
301c8d4c18bSChristian König 	else
3021d51775cSChristian König 		dma_resv_add_excl_fence(&resv, f);
3031d51775cSChristian König 	dma_resv_unlock(&resv);
3041d51775cSChristian König 
305*7bc80a54SChristian König 	r = dma_resv_get_fences(&resv, usage, &i, &fences);
3061d51775cSChristian König 	if (r) {
3071d51775cSChristian König 		pr_err("get_fences failed\n");
3081d51775cSChristian König 		goto err_free;
3091d51775cSChristian König 	}
3101d51775cSChristian König 
3111d51775cSChristian König 	if (i != 1 || fences[0] != f) {
31275ab2b36SChristian König 		pr_err("get_fences returned unexpected fence\n");
3131d51775cSChristian König 		goto err_free;
3141d51775cSChristian König 	}
3151d51775cSChristian König 
3161d51775cSChristian König 	dma_fence_signal(f);
3171d51775cSChristian König err_free:
3181d51775cSChristian König 	while (i--)
3191d51775cSChristian König 		dma_fence_put(fences[i]);
3201d51775cSChristian König 	kfree(fences);
32155d5e4f9SArnd Bergmann err_resv:
3221d51775cSChristian König 	dma_resv_fini(&resv);
3231d51775cSChristian König 	dma_fence_put(f);
3241d51775cSChristian König 	return r;
3251d51775cSChristian König }
3261d51775cSChristian König 
3271d51775cSChristian König static int test_excl_get_fences(void *arg)
3281d51775cSChristian König {
329*7bc80a54SChristian König 	return test_get_fences(arg, DMA_RESV_USAGE_WRITE);
3301d51775cSChristian König }
3311d51775cSChristian König 
3321d51775cSChristian König static int test_shared_get_fences(void *arg)
3331d51775cSChristian König {
334*7bc80a54SChristian König 	return test_get_fences(arg, DMA_RESV_USAGE_READ);
3351d51775cSChristian König }
3361d51775cSChristian König 
3371d51775cSChristian König int dma_resv(void)
3381d51775cSChristian König {
3391d51775cSChristian König 	static const struct subtest tests[] = {
3401d51775cSChristian König 		SUBTEST(sanitycheck),
3411d51775cSChristian König 		SUBTEST(test_excl_signaling),
3421d51775cSChristian König 		SUBTEST(test_shared_signaling),
3431d51775cSChristian König 		SUBTEST(test_excl_for_each),
3441d51775cSChristian König 		SUBTEST(test_shared_for_each),
3451d51775cSChristian König 		SUBTEST(test_excl_for_each_unlocked),
3461d51775cSChristian König 		SUBTEST(test_shared_for_each_unlocked),
3471d51775cSChristian König 		SUBTEST(test_excl_get_fences),
3481d51775cSChristian König 		SUBTEST(test_shared_get_fences),
3491d51775cSChristian König 	};
3501d51775cSChristian König 
3511d51775cSChristian König 	spin_lock_init(&fence_lock);
3521d51775cSChristian König 	return subtests(tests, NULL);
3531d51775cSChristian König }
354