Linux Audio

Check our new training course

Yocto / OpenEmbedded training

Mar 24-27, 2025, special US time zones
Register
Loading...
v6.8
  1/* SPDX-License-Identifier: MIT */
  2
  3/*
  4* Copyright © 2019 Intel Corporation
  5* 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	else
 58		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}
v6.2
  1/* SPDX-License-Identifier: MIT */
  2
  3/*
  4* Copyright © 2019 Intel Corporation
  5* 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	else
 58		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}