xref: /openbmc/linux/drivers/dma-buf/st-dma-resv.c (revision d62c43a9)
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 
fence_name(struct dma_fence * f)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 
alloc_fence(void)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 
sanitycheck(void * arg)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 
48*d62c43a9SArvind Yadav 	dma_fence_enable_sw_signaling(f);
49*d62c43a9SArvind Yadav 
501d51775cSChristian König 	dma_fence_signal(f);
511d51775cSChristian König 	dma_fence_put(f);
521d51775cSChristian König 
531d51775cSChristian König 	dma_resv_init(&resv);
541d51775cSChristian König 	r = dma_resv_lock(&resv, NULL);
551d51775cSChristian König 	if (r)
561d51775cSChristian König 		pr_err("Resv locking failed\n");
571d51775cSChristian König 	else
581d51775cSChristian König 		dma_resv_unlock(&resv);
591d51775cSChristian König 	dma_resv_fini(&resv);
601d51775cSChristian König 	return r;
611d51775cSChristian König }
621d51775cSChristian König 
test_signaling(void * arg)6373511edfSChristian König static int test_signaling(void *arg)
641d51775cSChristian König {
6573511edfSChristian König 	enum dma_resv_usage usage = (unsigned long)arg;
661d51775cSChristian König 	struct dma_resv resv;
671d51775cSChristian König 	struct dma_fence *f;
681d51775cSChristian König 	int r;
691d51775cSChristian König 
701d51775cSChristian König 	f = alloc_fence();
711d51775cSChristian König 	if (!f)
721d51775cSChristian König 		return -ENOMEM;
731d51775cSChristian König 
74*d62c43a9SArvind Yadav 	dma_fence_enable_sw_signaling(f);
75*d62c43a9SArvind Yadav 
761d51775cSChristian König 	dma_resv_init(&resv);
771d51775cSChristian König 	r = dma_resv_lock(&resv, NULL);
781d51775cSChristian König 	if (r) {
791d51775cSChristian König 		pr_err("Resv locking failed\n");
801d51775cSChristian König 		goto err_free;
811d51775cSChristian König 	}
821d51775cSChristian König 
83c8d4c18bSChristian König 	r = dma_resv_reserve_fences(&resv, 1);
841d51775cSChristian König 	if (r) {
851d51775cSChristian König 		pr_err("Resv shared slot allocation failed\n");
861d51775cSChristian König 		goto err_unlock;
871d51775cSChristian König 	}
881d51775cSChristian König 
8973511edfSChristian König 	dma_resv_add_fence(&resv, f, usage);
907bc80a54SChristian König 	if (dma_resv_test_signaled(&resv, usage)) {
911d51775cSChristian König 		pr_err("Resv unexpectedly signaled\n");
921d51775cSChristian König 		r = -EINVAL;
931d51775cSChristian König 		goto err_unlock;
941d51775cSChristian König 	}
951d51775cSChristian König 	dma_fence_signal(f);
967bc80a54SChristian König 	if (!dma_resv_test_signaled(&resv, usage)) {
971d51775cSChristian König 		pr_err("Resv not reporting signaled\n");
981d51775cSChristian König 		r = -EINVAL;
991d51775cSChristian König 		goto err_unlock;
1001d51775cSChristian König 	}
1011d51775cSChristian König err_unlock:
1021d51775cSChristian König 	dma_resv_unlock(&resv);
1031d51775cSChristian König err_free:
1041d51775cSChristian König 	dma_resv_fini(&resv);
1051d51775cSChristian König 	dma_fence_put(f);
1061d51775cSChristian König 	return r;
1071d51775cSChristian König }
1081d51775cSChristian König 
test_for_each(void * arg)10973511edfSChristian König static int test_for_each(void *arg)
1101d51775cSChristian König {
11173511edfSChristian König 	enum dma_resv_usage usage = (unsigned long)arg;
1121d51775cSChristian König 	struct dma_resv_iter cursor;
1131d51775cSChristian König 	struct dma_fence *f, *fence;
1141d51775cSChristian König 	struct dma_resv resv;
1151d51775cSChristian König 	int r;
1161d51775cSChristian König 
1171d51775cSChristian König 	f = alloc_fence();
1181d51775cSChristian König 	if (!f)
1191d51775cSChristian König 		return -ENOMEM;
1201d51775cSChristian König 
121*d62c43a9SArvind Yadav 	dma_fence_enable_sw_signaling(f);
122*d62c43a9SArvind Yadav 
1231d51775cSChristian König 	dma_resv_init(&resv);
1241d51775cSChristian König 	r = dma_resv_lock(&resv, NULL);
1251d51775cSChristian König 	if (r) {
1261d51775cSChristian König 		pr_err("Resv locking failed\n");
1271d51775cSChristian König 		goto err_free;
1281d51775cSChristian König 	}
1291d51775cSChristian König 
130c8d4c18bSChristian König 	r = dma_resv_reserve_fences(&resv, 1);
1311d51775cSChristian König 	if (r) {
1321d51775cSChristian König 		pr_err("Resv shared slot allocation failed\n");
1331d51775cSChristian König 		goto err_unlock;
1341d51775cSChristian König 	}
1351d51775cSChristian König 
13673511edfSChristian König 	dma_resv_add_fence(&resv, f, usage);
1371d51775cSChristian König 
1381d51775cSChristian König 	r = -ENOENT;
1397bc80a54SChristian König 	dma_resv_for_each_fence(&cursor, &resv, usage, fence) {
1401d51775cSChristian König 		if (!r) {
1411d51775cSChristian König 			pr_err("More than one fence found\n");
1421d51775cSChristian König 			r = -EINVAL;
1431d51775cSChristian König 			goto err_unlock;
1441d51775cSChristian König 		}
1451d51775cSChristian König 		if (f != fence) {
1461d51775cSChristian König 			pr_err("Unexpected fence\n");
1471d51775cSChristian König 			r = -EINVAL;
1481d51775cSChristian König 			goto err_unlock;
1491d51775cSChristian König 		}
15073511edfSChristian König 		if (dma_resv_iter_usage(&cursor) != usage) {
1511d51775cSChristian König 			pr_err("Unexpected fence usage\n");
1521d51775cSChristian König 			r = -EINVAL;
1531d51775cSChristian König 			goto err_unlock;
1541d51775cSChristian König 		}
1551d51775cSChristian König 		r = 0;
1561d51775cSChristian König 	}
1571d51775cSChristian König 	if (r) {
1581d51775cSChristian König 		pr_err("No fence found\n");
1591d51775cSChristian König 		goto err_unlock;
1601d51775cSChristian König 	}
1611d51775cSChristian König 	dma_fence_signal(f);
1621d51775cSChristian König err_unlock:
1631d51775cSChristian König 	dma_resv_unlock(&resv);
1641d51775cSChristian König err_free:
1651d51775cSChristian König 	dma_resv_fini(&resv);
1661d51775cSChristian König 	dma_fence_put(f);
1671d51775cSChristian König 	return r;
1681d51775cSChristian König }
1691d51775cSChristian König 
test_for_each_unlocked(void * arg)17073511edfSChristian König static int test_for_each_unlocked(void *arg)
1711d51775cSChristian König {
17273511edfSChristian König 	enum dma_resv_usage usage = (unsigned long)arg;
1731d51775cSChristian König 	struct dma_resv_iter cursor;
1741d51775cSChristian König 	struct dma_fence *f, *fence;
1751d51775cSChristian König 	struct dma_resv resv;
1761d51775cSChristian König 	int r;
1771d51775cSChristian König 
1781d51775cSChristian König 	f = alloc_fence();
1791d51775cSChristian König 	if (!f)
1801d51775cSChristian König 		return -ENOMEM;
1811d51775cSChristian König 
182*d62c43a9SArvind Yadav 	dma_fence_enable_sw_signaling(f);
183*d62c43a9SArvind Yadav 
1841d51775cSChristian König 	dma_resv_init(&resv);
1851d51775cSChristian König 	r = dma_resv_lock(&resv, NULL);
1861d51775cSChristian König 	if (r) {
1871d51775cSChristian König 		pr_err("Resv locking failed\n");
1881d51775cSChristian König 		goto err_free;
1891d51775cSChristian König 	}
1901d51775cSChristian König 
191c8d4c18bSChristian König 	r = dma_resv_reserve_fences(&resv, 1);
1921d51775cSChristian König 	if (r) {
1931d51775cSChristian König 		pr_err("Resv shared slot allocation failed\n");
1941d51775cSChristian König 		dma_resv_unlock(&resv);
1951d51775cSChristian König 		goto err_free;
1961d51775cSChristian König 	}
1971d51775cSChristian König 
19873511edfSChristian König 	dma_resv_add_fence(&resv, f, usage);
1991d51775cSChristian König 	dma_resv_unlock(&resv);
2001d51775cSChristian König 
2011d51775cSChristian König 	r = -ENOENT;
2027bc80a54SChristian König 	dma_resv_iter_begin(&cursor, &resv, usage);
2031d51775cSChristian König 	dma_resv_for_each_fence_unlocked(&cursor, fence) {
2041d51775cSChristian König 		if (!r) {
2051d51775cSChristian König 			pr_err("More than one fence found\n");
2061d51775cSChristian König 			r = -EINVAL;
2071d51775cSChristian König 			goto err_iter_end;
2081d51775cSChristian König 		}
2091d51775cSChristian König 		if (!dma_resv_iter_is_restarted(&cursor)) {
2101d51775cSChristian König 			pr_err("No restart flag\n");
2111d51775cSChristian König 			goto err_iter_end;
2121d51775cSChristian König 		}
2131d51775cSChristian König 		if (f != fence) {
2141d51775cSChristian König 			pr_err("Unexpected fence\n");
2151d51775cSChristian König 			r = -EINVAL;
2161d51775cSChristian König 			goto err_iter_end;
2171d51775cSChristian König 		}
21873511edfSChristian König 		if (dma_resv_iter_usage(&cursor) != usage) {
2191d51775cSChristian König 			pr_err("Unexpected fence usage\n");
2201d51775cSChristian König 			r = -EINVAL;
2211d51775cSChristian König 			goto err_iter_end;
2221d51775cSChristian König 		}
2231d51775cSChristian König 
2241d51775cSChristian König 		/* We use r as state here */
2251d51775cSChristian König 		if (r == -ENOENT) {
2261d51775cSChristian König 			r = -EINVAL;
2271d51775cSChristian König 			/* That should trigger an restart */
2288f94eda3SChristian König 			cursor.fences = (void*)~0;
2291d51775cSChristian König 		} else if (r == -EINVAL) {
2301d51775cSChristian König 			r = 0;
2311d51775cSChristian König 		}
2321d51775cSChristian König 	}
2331d51775cSChristian König 	if (r)
2341d51775cSChristian König 		pr_err("No fence found\n");
2351d51775cSChristian König err_iter_end:
2361d51775cSChristian König 	dma_resv_iter_end(&cursor);
2371d51775cSChristian König 	dma_fence_signal(f);
2381d51775cSChristian König err_free:
2391d51775cSChristian König 	dma_resv_fini(&resv);
2401d51775cSChristian König 	dma_fence_put(f);
2411d51775cSChristian König 	return r;
2421d51775cSChristian König }
2431d51775cSChristian König 
test_get_fences(void * arg)24473511edfSChristian König static int test_get_fences(void *arg)
2451d51775cSChristian König {
24673511edfSChristian König 	enum dma_resv_usage usage = (unsigned long)arg;
24775ab2b36SChristian König 	struct dma_fence *f, **fences = NULL;
2481d51775cSChristian König 	struct dma_resv resv;
2491d51775cSChristian König 	int r, i;
2501d51775cSChristian König 
2511d51775cSChristian König 	f = alloc_fence();
2521d51775cSChristian König 	if (!f)
2531d51775cSChristian König 		return -ENOMEM;
2541d51775cSChristian König 
255*d62c43a9SArvind Yadav 	dma_fence_enable_sw_signaling(f);
256*d62c43a9SArvind Yadav 
2571d51775cSChristian König 	dma_resv_init(&resv);
2581d51775cSChristian König 	r = dma_resv_lock(&resv, NULL);
2591d51775cSChristian König 	if (r) {
2601d51775cSChristian König 		pr_err("Resv locking failed\n");
26155d5e4f9SArnd Bergmann 		goto err_resv;
2621d51775cSChristian König 	}
2631d51775cSChristian König 
264c8d4c18bSChristian König 	r = dma_resv_reserve_fences(&resv, 1);
2651d51775cSChristian König 	if (r) {
2661d51775cSChristian König 		pr_err("Resv shared slot allocation failed\n");
2671d51775cSChristian König 		dma_resv_unlock(&resv);
26855d5e4f9SArnd Bergmann 		goto err_resv;
2691d51775cSChristian König 	}
2701d51775cSChristian König 
27173511edfSChristian König 	dma_resv_add_fence(&resv, f, usage);
2721d51775cSChristian König 	dma_resv_unlock(&resv);
2731d51775cSChristian König 
2747bc80a54SChristian König 	r = dma_resv_get_fences(&resv, usage, &i, &fences);
2751d51775cSChristian König 	if (r) {
2761d51775cSChristian König 		pr_err("get_fences failed\n");
2771d51775cSChristian König 		goto err_free;
2781d51775cSChristian König 	}
2791d51775cSChristian König 
2801d51775cSChristian König 	if (i != 1 || fences[0] != f) {
28175ab2b36SChristian König 		pr_err("get_fences returned unexpected fence\n");
2821d51775cSChristian König 		goto err_free;
2831d51775cSChristian König 	}
2841d51775cSChristian König 
2851d51775cSChristian König 	dma_fence_signal(f);
2861d51775cSChristian König err_free:
2871d51775cSChristian König 	while (i--)
2881d51775cSChristian König 		dma_fence_put(fences[i]);
2891d51775cSChristian König 	kfree(fences);
29055d5e4f9SArnd Bergmann err_resv:
2911d51775cSChristian König 	dma_resv_fini(&resv);
2921d51775cSChristian König 	dma_fence_put(f);
2931d51775cSChristian König 	return r;
2941d51775cSChristian König }
2951d51775cSChristian König 
dma_resv(void)2961d51775cSChristian König int dma_resv(void)
2971d51775cSChristian König {
2981d51775cSChristian König 	static const struct subtest tests[] = {
2991d51775cSChristian König 		SUBTEST(sanitycheck),
30073511edfSChristian König 		SUBTEST(test_signaling),
30173511edfSChristian König 		SUBTEST(test_for_each),
30273511edfSChristian König 		SUBTEST(test_for_each_unlocked),
30373511edfSChristian König 		SUBTEST(test_get_fences),
3041d51775cSChristian König 	};
30573511edfSChristian König 	enum dma_resv_usage usage;
30673511edfSChristian König 	int r;
3071d51775cSChristian König 
3081d51775cSChristian König 	spin_lock_init(&fence_lock);
3090cc848a7SChristian König 	for (usage = DMA_RESV_USAGE_KERNEL; usage <= DMA_RESV_USAGE_BOOKKEEP;
31073511edfSChristian König 	     ++usage) {
31173511edfSChristian König 		r = subtests(tests, (void *)(unsigned long)usage);
31273511edfSChristian König 		if (r)
31373511edfSChristian König 			return r;
31473511edfSChristian König 	}
31573511edfSChristian König 	return 0;
3161d51775cSChristian König }
317