brintos

brintos / linux-shallow public Read only

0
0
Text · 5.8 KiB · 15dbea1 Raw
317 lines · c
1/* SPDX-License-Identifier: MIT */2 3/*4* Copyright © 2019 Intel Corporation5* Copyright © 2021 Advanced Micro Devices, Inc.6*/7 8#include <linux/slab.h>9#include <linux/spinlock.h>10#include <linux/dma-resv.h>11 12#include "selftest.h"13 14static struct spinlock fence_lock;15 16static const char *fence_name(struct dma_fence *f)17{18	return "selftest";19}20 21static const struct dma_fence_ops fence_ops = {22	.get_driver_name = fence_name,23	.get_timeline_name = fence_name,24};25 26static struct dma_fence *alloc_fence(void)27{28	struct dma_fence *f;29 30	f = kmalloc(sizeof(*f), GFP_KERNEL);31	if (!f)32		return NULL;33 34	dma_fence_init(f, &fence_ops, &fence_lock, 0, 0);35	return f;36}37 38static int sanitycheck(void *arg)39{40	struct dma_resv resv;41	struct dma_fence *f;42	int r;43 44	f = alloc_fence();45	if (!f)46		return -ENOMEM;47 48	dma_fence_enable_sw_signaling(f);49 50	dma_fence_signal(f);51	dma_fence_put(f);52 53	dma_resv_init(&resv);54	r = dma_resv_lock(&resv, NULL);55	if (r)56		pr_err("Resv locking failed\n");57	else58		dma_resv_unlock(&resv);59	dma_resv_fini(&resv);60	return r;61}62 63static int test_signaling(void *arg)64{65	enum dma_resv_usage usage = (unsigned long)arg;66	struct dma_resv resv;67	struct dma_fence *f;68	int r;69 70	f = alloc_fence();71	if (!f)72		return -ENOMEM;73 74	dma_fence_enable_sw_signaling(f);75 76	dma_resv_init(&resv);77	r = dma_resv_lock(&resv, NULL);78	if (r) {79		pr_err("Resv locking failed\n");80		goto err_free;81	}82 83	r = dma_resv_reserve_fences(&resv, 1);84	if (r) {85		pr_err("Resv shared slot allocation failed\n");86		goto err_unlock;87	}88 89	dma_resv_add_fence(&resv, f, usage);90	if (dma_resv_test_signaled(&resv, usage)) {91		pr_err("Resv unexpectedly signaled\n");92		r = -EINVAL;93		goto err_unlock;94	}95	dma_fence_signal(f);96	if (!dma_resv_test_signaled(&resv, usage)) {97		pr_err("Resv not reporting signaled\n");98		r = -EINVAL;99		goto err_unlock;100	}101err_unlock:102	dma_resv_unlock(&resv);103err_free:104	dma_resv_fini(&resv);105	dma_fence_put(f);106	return r;107}108 109static int test_for_each(void *arg)110{111	enum dma_resv_usage usage = (unsigned long)arg;112	struct dma_resv_iter cursor;113	struct dma_fence *f, *fence;114	struct dma_resv resv;115	int r;116 117	f = alloc_fence();118	if (!f)119		return -ENOMEM;120 121	dma_fence_enable_sw_signaling(f);122 123	dma_resv_init(&resv);124	r = dma_resv_lock(&resv, NULL);125	if (r) {126		pr_err("Resv locking failed\n");127		goto err_free;128	}129 130	r = dma_resv_reserve_fences(&resv, 1);131	if (r) {132		pr_err("Resv shared slot allocation failed\n");133		goto err_unlock;134	}135 136	dma_resv_add_fence(&resv, f, usage);137 138	r = -ENOENT;139	dma_resv_for_each_fence(&cursor, &resv, usage, fence) {140		if (!r) {141			pr_err("More than one fence found\n");142			r = -EINVAL;143			goto err_unlock;144		}145		if (f != fence) {146			pr_err("Unexpected fence\n");147			r = -EINVAL;148			goto err_unlock;149		}150		if (dma_resv_iter_usage(&cursor) != usage) {151			pr_err("Unexpected fence usage\n");152			r = -EINVAL;153			goto err_unlock;154		}155		r = 0;156	}157	if (r) {158		pr_err("No fence found\n");159		goto err_unlock;160	}161	dma_fence_signal(f);162err_unlock:163	dma_resv_unlock(&resv);164err_free:165	dma_resv_fini(&resv);166	dma_fence_put(f);167	return r;168}169 170static int test_for_each_unlocked(void *arg)171{172	enum dma_resv_usage usage = (unsigned long)arg;173	struct dma_resv_iter cursor;174	struct dma_fence *f, *fence;175	struct dma_resv resv;176	int r;177 178	f = alloc_fence();179	if (!f)180		return -ENOMEM;181 182	dma_fence_enable_sw_signaling(f);183 184	dma_resv_init(&resv);185	r = dma_resv_lock(&resv, NULL);186	if (r) {187		pr_err("Resv locking failed\n");188		goto err_free;189	}190 191	r = dma_resv_reserve_fences(&resv, 1);192	if (r) {193		pr_err("Resv shared slot allocation failed\n");194		dma_resv_unlock(&resv);195		goto err_free;196	}197 198	dma_resv_add_fence(&resv, f, usage);199	dma_resv_unlock(&resv);200 201	r = -ENOENT;202	dma_resv_iter_begin(&cursor, &resv, usage);203	dma_resv_for_each_fence_unlocked(&cursor, fence) {204		if (!r) {205			pr_err("More than one fence found\n");206			r = -EINVAL;207			goto err_iter_end;208		}209		if (!dma_resv_iter_is_restarted(&cursor)) {210			pr_err("No restart flag\n");211			goto err_iter_end;212		}213		if (f != fence) {214			pr_err("Unexpected fence\n");215			r = -EINVAL;216			goto err_iter_end;217		}218		if (dma_resv_iter_usage(&cursor) != usage) {219			pr_err("Unexpected fence usage\n");220			r = -EINVAL;221			goto err_iter_end;222		}223 224		/* We use r as state here */225		if (r == -ENOENT) {226			r = -EINVAL;227			/* That should trigger an restart */228			cursor.fences = (void*)~0;229		} else if (r == -EINVAL) {230			r = 0;231		}232	}233	if (r)234		pr_err("No fence found\n");235err_iter_end:236	dma_resv_iter_end(&cursor);237	dma_fence_signal(f);238err_free:239	dma_resv_fini(&resv);240	dma_fence_put(f);241	return r;242}243 244static int test_get_fences(void *arg)245{246	enum dma_resv_usage usage = (unsigned long)arg;247	struct dma_fence *f, **fences = NULL;248	struct dma_resv resv;249	int r, i;250 251	f = alloc_fence();252	if (!f)253		return -ENOMEM;254 255	dma_fence_enable_sw_signaling(f);256 257	dma_resv_init(&resv);258	r = dma_resv_lock(&resv, NULL);259	if (r) {260		pr_err("Resv locking failed\n");261		goto err_resv;262	}263 264	r = dma_resv_reserve_fences(&resv, 1);265	if (r) {266		pr_err("Resv shared slot allocation failed\n");267		dma_resv_unlock(&resv);268		goto err_resv;269	}270 271	dma_resv_add_fence(&resv, f, usage);272	dma_resv_unlock(&resv);273 274	r = dma_resv_get_fences(&resv, usage, &i, &fences);275	if (r) {276		pr_err("get_fences failed\n");277		goto err_free;278	}279 280	if (i != 1 || fences[0] != f) {281		pr_err("get_fences returned unexpected fence\n");282		goto err_free;283	}284 285	dma_fence_signal(f);286err_free:287	while (i--)288		dma_fence_put(fences[i]);289	kfree(fences);290err_resv:291	dma_resv_fini(&resv);292	dma_fence_put(f);293	return r;294}295 296int dma_resv(void)297{298	static const struct subtest tests[] = {299		SUBTEST(sanitycheck),300		SUBTEST(test_signaling),301		SUBTEST(test_for_each),302		SUBTEST(test_for_each_unlocked),303		SUBTEST(test_get_fences),304	};305	enum dma_resv_usage usage;306	int r;307 308	spin_lock_init(&fence_lock);309	for (usage = DMA_RESV_USAGE_KERNEL; usage <= DMA_RESV_USAGE_BOOKKEEP;310	     ++usage) {311		r = subtests(tests, (void *)(unsigned long)usage);312		if (r)313			return r;314	}315	return 0;316}317