1 // SPDX-License-Identifier: MIT 2 3 /* 4 * Copyright (C) 2022 Advanced Micro Devices, Inc. 5 */ 6 7 #include <linux/dma-fence.h> 8 #include <linux/dma-fence-array.h> 9 #include <linux/dma-fence-chain.h> 10 #include <linux/dma-fence-unwrap.h> 11 12 #include "selftest.h" 13 14 #define CHAIN_SZ (4 << 10) 15 16 struct mock_fence { 17 struct dma_fence base; 18 spinlock_t lock; 19 }; 20 21 static const char *mock_name(struct dma_fence *f) 22 { 23 return "mock"; 24 } 25 26 static const struct dma_fence_ops mock_ops = { 27 .get_driver_name = mock_name, 28 .get_timeline_name = mock_name, 29 }; 30 31 static struct dma_fence *mock_fence(void) 32 { 33 struct mock_fence *f; 34 35 f = kmalloc(sizeof(*f), GFP_KERNEL); 36 if (!f) 37 return NULL; 38 39 spin_lock_init(&f->lock); 40 dma_fence_init(&f->base, &mock_ops, &f->lock, 41 dma_fence_context_alloc(1), 1); 42 43 return &f->base; 44 } 45 46 static struct dma_fence *mock_array(unsigned int num_fences, ...) 47 { 48 struct dma_fence_array *array; 49 struct dma_fence **fences; 50 va_list valist; 51 int i; 52 53 fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL); 54 if (!fences) 55 goto error_put; 56 57 va_start(valist, num_fences); 58 for (i = 0; i < num_fences; ++i) 59 fences[i] = va_arg(valist, typeof(*fences)); 60 va_end(valist); 61 62 array = dma_fence_array_create(num_fences, fences, 63 dma_fence_context_alloc(1), 64 1, false); 65 if (!array) 66 goto error_free; 67 return &array->base; 68 69 error_free: 70 kfree(fences); 71 72 error_put: 73 va_start(valist, num_fences); 74 for (i = 0; i < num_fences; ++i) 75 dma_fence_put(va_arg(valist, typeof(*fences))); 76 va_end(valist); 77 return NULL; 78 } 79 80 static struct dma_fence *mock_chain(struct dma_fence *prev, 81 struct dma_fence *fence) 82 { 83 struct dma_fence_chain *f; 84 85 f = dma_fence_chain_alloc(); 86 if (!f) { 87 dma_fence_put(prev); 88 dma_fence_put(fence); 89 return NULL; 90 } 91 92 dma_fence_chain_init(f, prev, fence, 1); 93 return &f->base; 94 } 95 96 static int sanitycheck(void *arg) 97 { 98 struct dma_fence *f, *chain, *array; 99 int err = 0; 100 101 f = mock_fence(); 102 if (!f) 103 return -ENOMEM; 104 105 array = mock_array(1, f); 106 if (!array) 107 return -ENOMEM; 108 109 chain = mock_chain(NULL, array); 110 if (!chain) 111 return -ENOMEM; 112 113 dma_fence_put(chain); 114 return err; 115 } 116 117 static int unwrap_array(void *arg) 118 { 119 struct dma_fence *fence, *f1, *f2, *array; 120 struct dma_fence_unwrap iter; 121 int err = 0; 122 123 f1 = mock_fence(); 124 if (!f1) 125 return -ENOMEM; 126 127 f2 = mock_fence(); 128 if (!f2) { 129 dma_fence_put(f1); 130 return -ENOMEM; 131 } 132 133 array = mock_array(2, f1, f2); 134 if (!array) 135 return -ENOMEM; 136 137 dma_fence_unwrap_for_each(fence, &iter, array) { 138 if (fence == f1) { 139 f1 = NULL; 140 } else if (fence == f2) { 141 f2 = NULL; 142 } else { 143 pr_err("Unexpected fence!\n"); 144 err = -EINVAL; 145 } 146 } 147 148 if (f1 || f2) { 149 pr_err("Not all fences seen!\n"); 150 err = -EINVAL; 151 } 152 153 dma_fence_put(array); 154 return err; 155 } 156 157 static int unwrap_chain(void *arg) 158 { 159 struct dma_fence *fence, *f1, *f2, *chain; 160 struct dma_fence_unwrap iter; 161 int err = 0; 162 163 f1 = mock_fence(); 164 if (!f1) 165 return -ENOMEM; 166 167 f2 = mock_fence(); 168 if (!f2) { 169 dma_fence_put(f1); 170 return -ENOMEM; 171 } 172 173 chain = mock_chain(f1, f2); 174 if (!chain) 175 return -ENOMEM; 176 177 dma_fence_unwrap_for_each(fence, &iter, chain) { 178 if (fence == f1) { 179 f1 = NULL; 180 } else if (fence == f2) { 181 f2 = NULL; 182 } else { 183 pr_err("Unexpected fence!\n"); 184 err = -EINVAL; 185 } 186 } 187 188 if (f1 || f2) { 189 pr_err("Not all fences seen!\n"); 190 err = -EINVAL; 191 } 192 193 dma_fence_put(chain); 194 return err; 195 } 196 197 static int unwrap_chain_array(void *arg) 198 { 199 struct dma_fence *fence, *f1, *f2, *array, *chain; 200 struct dma_fence_unwrap iter; 201 int err = 0; 202 203 f1 = mock_fence(); 204 if (!f1) 205 return -ENOMEM; 206 207 f2 = mock_fence(); 208 if (!f2) { 209 dma_fence_put(f1); 210 return -ENOMEM; 211 } 212 213 array = mock_array(2, f1, f2); 214 if (!array) 215 return -ENOMEM; 216 217 chain = mock_chain(NULL, array); 218 if (!chain) 219 return -ENOMEM; 220 221 dma_fence_unwrap_for_each(fence, &iter, chain) { 222 if (fence == f1) { 223 f1 = NULL; 224 } else if (fence == f2) { 225 f2 = NULL; 226 } else { 227 pr_err("Unexpected fence!\n"); 228 err = -EINVAL; 229 } 230 } 231 232 if (f1 || f2) { 233 pr_err("Not all fences seen!\n"); 234 err = -EINVAL; 235 } 236 237 dma_fence_put(chain); 238 return err; 239 } 240 241 static int unwrap_merge(void *arg) 242 { 243 struct dma_fence *fence, *f1, *f2, *f3; 244 struct dma_fence_unwrap iter; 245 int err = 0; 246 247 f1 = mock_fence(); 248 if (!f1) 249 return -ENOMEM; 250 251 f2 = mock_fence(); 252 if (!f2) { 253 err = -ENOMEM; 254 goto error_put_f1; 255 } 256 257 f3 = dma_fence_unwrap_merge(f1, f2); 258 if (!f3) { 259 err = -ENOMEM; 260 goto error_put_f2; 261 } 262 263 dma_fence_unwrap_for_each(fence, &iter, f3) { 264 if (fence == f1) { 265 dma_fence_put(f1); 266 f1 = NULL; 267 } else if (fence == f2) { 268 dma_fence_put(f2); 269 f2 = NULL; 270 } else { 271 pr_err("Unexpected fence!\n"); 272 err = -EINVAL; 273 } 274 } 275 276 if (f1 || f2) { 277 pr_err("Not all fences seen!\n"); 278 err = -EINVAL; 279 } 280 281 dma_fence_put(f3); 282 error_put_f2: 283 dma_fence_put(f2); 284 error_put_f1: 285 dma_fence_put(f1); 286 return err; 287 } 288 289 static int unwrap_merge_complex(void *arg) 290 { 291 struct dma_fence *fence, *f1, *f2, *f3, *f4, *f5; 292 struct dma_fence_unwrap iter; 293 int err = -ENOMEM; 294 295 f1 = mock_fence(); 296 if (!f1) 297 return -ENOMEM; 298 299 f2 = mock_fence(); 300 if (!f2) 301 goto error_put_f1; 302 303 f3 = dma_fence_unwrap_merge(f1, f2); 304 if (!f3) 305 goto error_put_f2; 306 307 /* The resulting array has the fences in reverse */ 308 f4 = dma_fence_unwrap_merge(f2, f1); 309 if (!f4) 310 goto error_put_f3; 311 312 /* Signaled fences should be filtered, the two arrays merged. */ 313 f5 = dma_fence_unwrap_merge(f3, f4, dma_fence_get_stub()); 314 if (!f5) 315 goto error_put_f4; 316 317 err = 0; 318 dma_fence_unwrap_for_each(fence, &iter, f5) { 319 if (fence == f1) { 320 dma_fence_put(f1); 321 f1 = NULL; 322 } else if (fence == f2) { 323 dma_fence_put(f2); 324 f2 = NULL; 325 } else { 326 pr_err("Unexpected fence!\n"); 327 err = -EINVAL; 328 } 329 } 330 331 if (f1 || f2) { 332 pr_err("Not all fences seen!\n"); 333 err = -EINVAL; 334 } 335 336 dma_fence_put(f5); 337 error_put_f4: 338 dma_fence_put(f4); 339 error_put_f3: 340 dma_fence_put(f3); 341 error_put_f2: 342 dma_fence_put(f2); 343 error_put_f1: 344 dma_fence_put(f1); 345 return err; 346 } 347 348 int dma_fence_unwrap(void) 349 { 350 static const struct subtest tests[] = { 351 SUBTEST(sanitycheck), 352 SUBTEST(unwrap_array), 353 SUBTEST(unwrap_chain), 354 SUBTEST(unwrap_chain_array), 355 SUBTEST(unwrap_merge), 356 SUBTEST(unwrap_merge_complex), 357 }; 358 359 return subtests(tests, NULL); 360 } 361