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