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