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 14 static struct spinlock fence_lock; 15 16 static const char *fence_name(struct dma_fence *f) 17 { 18 return "selftest"; 19 } 20 21 static const struct dma_fence_ops fence_ops = { 22 .get_driver_name = fence_name, 23 .get_timeline_name = fence_name, 24 }; 25 26 static 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 38 static 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 63 static 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 } 101 err_unlock: 102 dma_resv_unlock(&resv); 103 err_free: 104 dma_resv_fini(&resv); 105 dma_fence_put(f); 106 return r; 107 } 108 109 static 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); 162 err_unlock: 163 dma_resv_unlock(&resv); 164 err_free: 165 dma_resv_fini(&resv); 166 dma_fence_put(f); 167 return r; 168 } 169 170 static 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"); 235 err_iter_end: 236 dma_resv_iter_end(&cursor); 237 dma_fence_signal(f); 238 err_free: 239 dma_resv_fini(&resv); 240 dma_fence_put(f); 241 return r; 242 } 243 244 static 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); 286 err_free: 287 while (i--) 288 dma_fence_put(fences[i]); 289 kfree(fences); 290 err_resv: 291 dma_resv_fini(&resv); 292 dma_fence_put(f); 293 return r; 294 } 295 296 int 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