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 dma_fence_enable_sw_signaling(f); 106 107 array = mock_array(1, f); 108 if (!array) 109 return -ENOMEM; 110 111 chain = mock_chain(NULL, array); 112 if (!chain) 113 return -ENOMEM; 114 115 dma_fence_put(chain); 116 return err; 117 } 118 119 static int unwrap_array(void *arg) 120 { 121 struct dma_fence *fence, *f1, *f2, *array; 122 struct dma_fence_unwrap iter; 123 int err = 0; 124 125 f1 = mock_fence(); 126 if (!f1) 127 return -ENOMEM; 128 129 dma_fence_enable_sw_signaling(f1); 130 131 f2 = mock_fence(); 132 if (!f2) { 133 dma_fence_put(f1); 134 return -ENOMEM; 135 } 136 137 dma_fence_enable_sw_signaling(f2); 138 139 array = mock_array(2, f1, f2); 140 if (!array) 141 return -ENOMEM; 142 143 dma_fence_unwrap_for_each(fence, &iter, array) { 144 if (fence == f1) { 145 f1 = NULL; 146 } else if (fence == f2) { 147 f2 = NULL; 148 } else { 149 pr_err("Unexpected fence!\n"); 150 err = -EINVAL; 151 } 152 } 153 154 if (f1 || f2) { 155 pr_err("Not all fences seen!\n"); 156 err = -EINVAL; 157 } 158 159 dma_fence_put(array); 160 return err; 161 } 162 163 static int unwrap_chain(void *arg) 164 { 165 struct dma_fence *fence, *f1, *f2, *chain; 166 struct dma_fence_unwrap iter; 167 int err = 0; 168 169 f1 = mock_fence(); 170 if (!f1) 171 return -ENOMEM; 172 173 dma_fence_enable_sw_signaling(f1); 174 175 f2 = mock_fence(); 176 if (!f2) { 177 dma_fence_put(f1); 178 return -ENOMEM; 179 } 180 181 dma_fence_enable_sw_signaling(f2); 182 183 chain = mock_chain(f1, f2); 184 if (!chain) 185 return -ENOMEM; 186 187 dma_fence_unwrap_for_each(fence, &iter, chain) { 188 if (fence == f1) { 189 f1 = NULL; 190 } else if (fence == f2) { 191 f2 = NULL; 192 } else { 193 pr_err("Unexpected fence!\n"); 194 err = -EINVAL; 195 } 196 } 197 198 if (f1 || f2) { 199 pr_err("Not all fences seen!\n"); 200 err = -EINVAL; 201 } 202 203 dma_fence_put(chain); 204 return err; 205 } 206 207 static int unwrap_chain_array(void *arg) 208 { 209 struct dma_fence *fence, *f1, *f2, *array, *chain; 210 struct dma_fence_unwrap iter; 211 int err = 0; 212 213 f1 = mock_fence(); 214 if (!f1) 215 return -ENOMEM; 216 217 dma_fence_enable_sw_signaling(f1); 218 219 f2 = mock_fence(); 220 if (!f2) { 221 dma_fence_put(f1); 222 return -ENOMEM; 223 } 224 225 dma_fence_enable_sw_signaling(f2); 226 227 array = mock_array(2, f1, f2); 228 if (!array) 229 return -ENOMEM; 230 231 chain = mock_chain(NULL, array); 232 if (!chain) 233 return -ENOMEM; 234 235 dma_fence_unwrap_for_each(fence, &iter, chain) { 236 if (fence == f1) { 237 f1 = NULL; 238 } else if (fence == f2) { 239 f2 = NULL; 240 } else { 241 pr_err("Unexpected fence!\n"); 242 err = -EINVAL; 243 } 244 } 245 246 if (f1 || f2) { 247 pr_err("Not all fences seen!\n"); 248 err = -EINVAL; 249 } 250 251 dma_fence_put(chain); 252 return err; 253 } 254 255 static int unwrap_merge(void *arg) 256 { 257 struct dma_fence *fence, *f1, *f2, *f3; 258 struct dma_fence_unwrap iter; 259 int err = 0; 260 261 f1 = mock_fence(); 262 if (!f1) 263 return -ENOMEM; 264 265 dma_fence_enable_sw_signaling(f1); 266 267 f2 = mock_fence(); 268 if (!f2) { 269 err = -ENOMEM; 270 goto error_put_f1; 271 } 272 273 dma_fence_enable_sw_signaling(f2); 274 275 f3 = dma_fence_unwrap_merge(f1, f2); 276 if (!f3) { 277 err = -ENOMEM; 278 goto error_put_f2; 279 } 280 281 dma_fence_unwrap_for_each(fence, &iter, f3) { 282 if (fence == f1) { 283 dma_fence_put(f1); 284 f1 = NULL; 285 } else if (fence == f2) { 286 dma_fence_put(f2); 287 f2 = NULL; 288 } else { 289 pr_err("Unexpected fence!\n"); 290 err = -EINVAL; 291 } 292 } 293 294 if (f1 || f2) { 295 pr_err("Not all fences seen!\n"); 296 err = -EINVAL; 297 } 298 299 dma_fence_put(f3); 300 error_put_f2: 301 dma_fence_put(f2); 302 error_put_f1: 303 dma_fence_put(f1); 304 return err; 305 } 306 307 static int unwrap_merge_complex(void *arg) 308 { 309 struct dma_fence *fence, *f1, *f2, *f3, *f4, *f5; 310 struct dma_fence_unwrap iter; 311 int err = -ENOMEM; 312 313 f1 = mock_fence(); 314 if (!f1) 315 return -ENOMEM; 316 317 dma_fence_enable_sw_signaling(f1); 318 319 f2 = mock_fence(); 320 if (!f2) 321 goto error_put_f1; 322 323 dma_fence_enable_sw_signaling(f2); 324 325 f3 = dma_fence_unwrap_merge(f1, f2); 326 if (!f3) 327 goto error_put_f2; 328 329 /* The resulting array has the fences in reverse */ 330 f4 = dma_fence_unwrap_merge(f2, f1); 331 if (!f4) 332 goto error_put_f3; 333 334 /* Signaled fences should be filtered, the two arrays merged. */ 335 f5 = dma_fence_unwrap_merge(f3, f4, dma_fence_get_stub()); 336 if (!f5) 337 goto error_put_f4; 338 339 err = 0; 340 dma_fence_unwrap_for_each(fence, &iter, f5) { 341 if (fence == f1) { 342 dma_fence_put(f1); 343 f1 = NULL; 344 } else if (fence == f2) { 345 dma_fence_put(f2); 346 f2 = NULL; 347 } else { 348 pr_err("Unexpected fence!\n"); 349 err = -EINVAL; 350 } 351 } 352 353 if (f1 || f2) { 354 pr_err("Not all fences seen!\n"); 355 err = -EINVAL; 356 } 357 358 dma_fence_put(f5); 359 error_put_f4: 360 dma_fence_put(f4); 361 error_put_f3: 362 dma_fence_put(f3); 363 error_put_f2: 364 dma_fence_put(f2); 365 error_put_f1: 366 dma_fence_put(f1); 367 return err; 368 } 369 370 int dma_fence_unwrap(void) 371 { 372 static const struct subtest tests[] = { 373 SUBTEST(sanitycheck), 374 SUBTEST(unwrap_array), 375 SUBTEST(unwrap_chain), 376 SUBTEST(unwrap_chain_array), 377 SUBTEST(unwrap_merge), 378 SUBTEST(unwrap_merge_complex), 379 }; 380 381 return subtests(tests, NULL); 382 } 383