123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382 |
- // SPDX-License-Identifier: MIT
- /*
- * Copyright (C) 2022 Advanced Micro Devices, Inc.
- */
- #include <linux/dma-fence.h>
- #include <linux/dma-fence-array.h>
- #include <linux/dma-fence-chain.h>
- #include <linux/dma-fence-unwrap.h>
- #include "selftest.h"
- #define CHAIN_SZ (4 << 10)
- struct mock_fence {
- struct dma_fence base;
- spinlock_t lock;
- };
- static const char *mock_name(struct dma_fence *f)
- {
- return "mock";
- }
- static const struct dma_fence_ops mock_ops = {
- .get_driver_name = mock_name,
- .get_timeline_name = mock_name,
- };
- static struct dma_fence *mock_fence(void)
- {
- struct mock_fence *f;
- f = kmalloc(sizeof(*f), GFP_KERNEL);
- if (!f)
- return NULL;
- spin_lock_init(&f->lock);
- dma_fence_init(&f->base, &mock_ops, &f->lock,
- dma_fence_context_alloc(1), 1);
- return &f->base;
- }
- static struct dma_fence *mock_array(unsigned int num_fences, ...)
- {
- struct dma_fence_array *array;
- struct dma_fence **fences;
- va_list valist;
- int i;
- fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
- if (!fences)
- goto error_put;
- va_start(valist, num_fences);
- for (i = 0; i < num_fences; ++i)
- fences[i] = va_arg(valist, typeof(*fences));
- va_end(valist);
- array = dma_fence_array_create(num_fences, fences,
- dma_fence_context_alloc(1),
- 1, false);
- if (!array)
- goto error_free;
- return &array->base;
- error_free:
- kfree(fences);
- error_put:
- va_start(valist, num_fences);
- for (i = 0; i < num_fences; ++i)
- dma_fence_put(va_arg(valist, typeof(*fences)));
- va_end(valist);
- return NULL;
- }
- static struct dma_fence *mock_chain(struct dma_fence *prev,
- struct dma_fence *fence)
- {
- struct dma_fence_chain *f;
- f = dma_fence_chain_alloc();
- if (!f) {
- dma_fence_put(prev);
- dma_fence_put(fence);
- return NULL;
- }
- dma_fence_chain_init(f, prev, fence, 1);
- return &f->base;
- }
- static int sanitycheck(void *arg)
- {
- struct dma_fence *f, *chain, *array;
- int err = 0;
- f = mock_fence();
- if (!f)
- return -ENOMEM;
- dma_fence_enable_sw_signaling(f);
- array = mock_array(1, f);
- if (!array)
- return -ENOMEM;
- chain = mock_chain(NULL, array);
- if (!chain)
- return -ENOMEM;
- dma_fence_put(chain);
- return err;
- }
- static int unwrap_array(void *arg)
- {
- struct dma_fence *fence, *f1, *f2, *array;
- struct dma_fence_unwrap iter;
- int err = 0;
- f1 = mock_fence();
- if (!f1)
- return -ENOMEM;
- dma_fence_enable_sw_signaling(f1);
- f2 = mock_fence();
- if (!f2) {
- dma_fence_put(f1);
- return -ENOMEM;
- }
- dma_fence_enable_sw_signaling(f2);
- array = mock_array(2, f1, f2);
- if (!array)
- return -ENOMEM;
- dma_fence_unwrap_for_each(fence, &iter, array) {
- if (fence == f1) {
- f1 = NULL;
- } else if (fence == f2) {
- f2 = NULL;
- } else {
- pr_err("Unexpected fence!\n");
- err = -EINVAL;
- }
- }
- if (f1 || f2) {
- pr_err("Not all fences seen!\n");
- err = -EINVAL;
- }
- dma_fence_put(array);
- return err;
- }
- static int unwrap_chain(void *arg)
- {
- struct dma_fence *fence, *f1, *f2, *chain;
- struct dma_fence_unwrap iter;
- int err = 0;
- f1 = mock_fence();
- if (!f1)
- return -ENOMEM;
- dma_fence_enable_sw_signaling(f1);
- f2 = mock_fence();
- if (!f2) {
- dma_fence_put(f1);
- return -ENOMEM;
- }
- dma_fence_enable_sw_signaling(f2);
- chain = mock_chain(f1, f2);
- if (!chain)
- return -ENOMEM;
- dma_fence_unwrap_for_each(fence, &iter, chain) {
- if (fence == f1) {
- f1 = NULL;
- } else if (fence == f2) {
- f2 = NULL;
- } else {
- pr_err("Unexpected fence!\n");
- err = -EINVAL;
- }
- }
- if (f1 || f2) {
- pr_err("Not all fences seen!\n");
- err = -EINVAL;
- }
- dma_fence_put(chain);
- return err;
- }
- static int unwrap_chain_array(void *arg)
- {
- struct dma_fence *fence, *f1, *f2, *array, *chain;
- struct dma_fence_unwrap iter;
- int err = 0;
- f1 = mock_fence();
- if (!f1)
- return -ENOMEM;
- dma_fence_enable_sw_signaling(f1);
- f2 = mock_fence();
- if (!f2) {
- dma_fence_put(f1);
- return -ENOMEM;
- }
- dma_fence_enable_sw_signaling(f2);
- array = mock_array(2, f1, f2);
- if (!array)
- return -ENOMEM;
- chain = mock_chain(NULL, array);
- if (!chain)
- return -ENOMEM;
- dma_fence_unwrap_for_each(fence, &iter, chain) {
- if (fence == f1) {
- f1 = NULL;
- } else if (fence == f2) {
- f2 = NULL;
- } else {
- pr_err("Unexpected fence!\n");
- err = -EINVAL;
- }
- }
- if (f1 || f2) {
- pr_err("Not all fences seen!\n");
- err = -EINVAL;
- }
- dma_fence_put(chain);
- return err;
- }
- static int unwrap_merge(void *arg)
- {
- struct dma_fence *fence, *f1, *f2, *f3;
- struct dma_fence_unwrap iter;
- int err = 0;
- f1 = mock_fence();
- if (!f1)
- return -ENOMEM;
- dma_fence_enable_sw_signaling(f1);
- f2 = mock_fence();
- if (!f2) {
- err = -ENOMEM;
- goto error_put_f1;
- }
- dma_fence_enable_sw_signaling(f2);
- f3 = dma_fence_unwrap_merge(f1, f2);
- if (!f3) {
- err = -ENOMEM;
- goto error_put_f2;
- }
- dma_fence_unwrap_for_each(fence, &iter, f3) {
- if (fence == f1) {
- dma_fence_put(f1);
- f1 = NULL;
- } else if (fence == f2) {
- dma_fence_put(f2);
- f2 = NULL;
- } else {
- pr_err("Unexpected fence!\n");
- err = -EINVAL;
- }
- }
- if (f1 || f2) {
- pr_err("Not all fences seen!\n");
- err = -EINVAL;
- }
- dma_fence_put(f3);
- error_put_f2:
- dma_fence_put(f2);
- error_put_f1:
- dma_fence_put(f1);
- return err;
- }
- static int unwrap_merge_complex(void *arg)
- {
- struct dma_fence *fence, *f1, *f2, *f3, *f4, *f5;
- struct dma_fence_unwrap iter;
- int err = -ENOMEM;
- f1 = mock_fence();
- if (!f1)
- return -ENOMEM;
- dma_fence_enable_sw_signaling(f1);
- f2 = mock_fence();
- if (!f2)
- goto error_put_f1;
- dma_fence_enable_sw_signaling(f2);
- f3 = dma_fence_unwrap_merge(f1, f2);
- if (!f3)
- goto error_put_f2;
- /* The resulting array has the fences in reverse */
- f4 = dma_fence_unwrap_merge(f2, f1);
- if (!f4)
- goto error_put_f3;
- /* Signaled fences should be filtered, the two arrays merged. */
- f5 = dma_fence_unwrap_merge(f3, f4, dma_fence_get_stub());
- if (!f5)
- goto error_put_f4;
- err = 0;
- dma_fence_unwrap_for_each(fence, &iter, f5) {
- if (fence == f1) {
- dma_fence_put(f1);
- f1 = NULL;
- } else if (fence == f2) {
- dma_fence_put(f2);
- f2 = NULL;
- } else {
- pr_err("Unexpected fence!\n");
- err = -EINVAL;
- }
- }
- if (f1 || f2) {
- pr_err("Not all fences seen!\n");
- err = -EINVAL;
- }
- dma_fence_put(f5);
- error_put_f4:
- dma_fence_put(f4);
- error_put_f3:
- dma_fence_put(f3);
- error_put_f2:
- dma_fence_put(f2);
- error_put_f1:
- dma_fence_put(f1);
- return err;
- }
- int dma_fence_unwrap(void)
- {
- static const struct subtest tests[] = {
- SUBTEST(sanitycheck),
- SUBTEST(unwrap_array),
- SUBTEST(unwrap_chain),
- SUBTEST(unwrap_chain_array),
- SUBTEST(unwrap_merge),
- SUBTEST(unwrap_merge_complex),
- };
- return subtests(tests, NULL);
- }
|