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} 317