st-dma-resv.c (5782B)
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_signal(f); 49 dma_fence_put(f); 50 51 dma_resv_init(&resv); 52 r = dma_resv_lock(&resv, NULL); 53 if (r) 54 pr_err("Resv locking failed\n"); 55 else 56 dma_resv_unlock(&resv); 57 dma_resv_fini(&resv); 58 return r; 59} 60 61static int test_signaling(void *arg) 62{ 63 enum dma_resv_usage usage = (unsigned long)arg; 64 struct dma_resv resv; 65 struct dma_fence *f; 66 int r; 67 68 f = alloc_fence(); 69 if (!f) 70 return -ENOMEM; 71 72 dma_resv_init(&resv); 73 r = dma_resv_lock(&resv, NULL); 74 if (r) { 75 pr_err("Resv locking failed\n"); 76 goto err_free; 77 } 78 79 r = dma_resv_reserve_fences(&resv, 1); 80 if (r) { 81 pr_err("Resv shared slot allocation failed\n"); 82 goto err_unlock; 83 } 84 85 dma_resv_add_fence(&resv, f, usage); 86 if (dma_resv_test_signaled(&resv, usage)) { 87 pr_err("Resv unexpectedly signaled\n"); 88 r = -EINVAL; 89 goto err_unlock; 90 } 91 dma_fence_signal(f); 92 if (!dma_resv_test_signaled(&resv, usage)) { 93 pr_err("Resv not reporting signaled\n"); 94 r = -EINVAL; 95 goto err_unlock; 96 } 97err_unlock: 98 dma_resv_unlock(&resv); 99err_free: 100 dma_resv_fini(&resv); 101 dma_fence_put(f); 102 return r; 103} 104 105static int test_for_each(void *arg) 106{ 107 enum dma_resv_usage usage = (unsigned long)arg; 108 struct dma_resv_iter cursor; 109 struct dma_fence *f, *fence; 110 struct dma_resv resv; 111 int r; 112 113 f = alloc_fence(); 114 if (!f) 115 return -ENOMEM; 116 117 dma_resv_init(&resv); 118 r = dma_resv_lock(&resv, NULL); 119 if (r) { 120 pr_err("Resv locking failed\n"); 121 goto err_free; 122 } 123 124 r = dma_resv_reserve_fences(&resv, 1); 125 if (r) { 126 pr_err("Resv shared slot allocation failed\n"); 127 goto err_unlock; 128 } 129 130 dma_resv_add_fence(&resv, f, usage); 131 132 r = -ENOENT; 133 dma_resv_for_each_fence(&cursor, &resv, usage, fence) { 134 if (!r) { 135 pr_err("More than one fence found\n"); 136 r = -EINVAL; 137 goto err_unlock; 138 } 139 if (f != fence) { 140 pr_err("Unexpected fence\n"); 141 r = -EINVAL; 142 goto err_unlock; 143 } 144 if (dma_resv_iter_usage(&cursor) != usage) { 145 pr_err("Unexpected fence usage\n"); 146 r = -EINVAL; 147 goto err_unlock; 148 } 149 r = 0; 150 } 151 if (r) { 152 pr_err("No fence found\n"); 153 goto err_unlock; 154 } 155 dma_fence_signal(f); 156err_unlock: 157 dma_resv_unlock(&resv); 158err_free: 159 dma_resv_fini(&resv); 160 dma_fence_put(f); 161 return r; 162} 163 164static int test_for_each_unlocked(void *arg) 165{ 166 enum dma_resv_usage usage = (unsigned long)arg; 167 struct dma_resv_iter cursor; 168 struct dma_fence *f, *fence; 169 struct dma_resv resv; 170 int r; 171 172 f = alloc_fence(); 173 if (!f) 174 return -ENOMEM; 175 176 dma_resv_init(&resv); 177 r = dma_resv_lock(&resv, NULL); 178 if (r) { 179 pr_err("Resv locking failed\n"); 180 goto err_free; 181 } 182 183 r = dma_resv_reserve_fences(&resv, 1); 184 if (r) { 185 pr_err("Resv shared slot allocation failed\n"); 186 dma_resv_unlock(&resv); 187 goto err_free; 188 } 189 190 dma_resv_add_fence(&resv, f, usage); 191 dma_resv_unlock(&resv); 192 193 r = -ENOENT; 194 dma_resv_iter_begin(&cursor, &resv, usage); 195 dma_resv_for_each_fence_unlocked(&cursor, fence) { 196 if (!r) { 197 pr_err("More than one fence found\n"); 198 r = -EINVAL; 199 goto err_iter_end; 200 } 201 if (!dma_resv_iter_is_restarted(&cursor)) { 202 pr_err("No restart flag\n"); 203 goto err_iter_end; 204 } 205 if (f != fence) { 206 pr_err("Unexpected fence\n"); 207 r = -EINVAL; 208 goto err_iter_end; 209 } 210 if (dma_resv_iter_usage(&cursor) != usage) { 211 pr_err("Unexpected fence usage\n"); 212 r = -EINVAL; 213 goto err_iter_end; 214 } 215 216 /* We use r as state here */ 217 if (r == -ENOENT) { 218 r = -EINVAL; 219 /* That should trigger an restart */ 220 cursor.fences = (void*)~0; 221 } else if (r == -EINVAL) { 222 r = 0; 223 } 224 } 225 if (r) 226 pr_err("No fence found\n"); 227err_iter_end: 228 dma_resv_iter_end(&cursor); 229 dma_fence_signal(f); 230err_free: 231 dma_resv_fini(&resv); 232 dma_fence_put(f); 233 return r; 234} 235 236static int test_get_fences(void *arg) 237{ 238 enum dma_resv_usage usage = (unsigned long)arg; 239 struct dma_fence *f, **fences = NULL; 240 struct dma_resv resv; 241 int r, i; 242 243 f = alloc_fence(); 244 if (!f) 245 return -ENOMEM; 246 247 dma_resv_init(&resv); 248 r = dma_resv_lock(&resv, NULL); 249 if (r) { 250 pr_err("Resv locking failed\n"); 251 goto err_resv; 252 } 253 254 r = dma_resv_reserve_fences(&resv, 1); 255 if (r) { 256 pr_err("Resv shared slot allocation failed\n"); 257 dma_resv_unlock(&resv); 258 goto err_resv; 259 } 260 261 dma_resv_add_fence(&resv, f, usage); 262 dma_resv_unlock(&resv); 263 264 r = dma_resv_get_fences(&resv, usage, &i, &fences); 265 if (r) { 266 pr_err("get_fences failed\n"); 267 goto err_free; 268 } 269 270 if (i != 1 || fences[0] != f) { 271 pr_err("get_fences returned unexpected fence\n"); 272 goto err_free; 273 } 274 275 dma_fence_signal(f); 276err_free: 277 while (i--) 278 dma_fence_put(fences[i]); 279 kfree(fences); 280err_resv: 281 dma_resv_fini(&resv); 282 dma_fence_put(f); 283 return r; 284} 285 286int dma_resv(void) 287{ 288 static const struct subtest tests[] = { 289 SUBTEST(sanitycheck), 290 SUBTEST(test_signaling), 291 SUBTEST(test_for_each), 292 SUBTEST(test_for_each_unlocked), 293 SUBTEST(test_get_fences), 294 }; 295 enum dma_resv_usage usage; 296 int r; 297 298 spin_lock_init(&fence_lock); 299 for (usage = DMA_RESV_USAGE_KERNEL; usage <= DMA_RESV_USAGE_BOOKKEEP; 300 ++usage) { 301 r = subtests(tests, (void *)(unsigned long)usage); 302 if (r) 303 return r; 304 } 305 return 0; 306}