1 // SPDX-License-Identifier: MIT 2 3 /* 4 * Copyright (C) 2022 Advanced Micro Devices, Inc. 5 */ 6 7 #include <linux/dma-fence-unwrap.h> 8 #if 0 9 #include <linux/kernel.h> 10 #include <linux/kthread.h> 11 #include <linux/mm.h> 12 #include <linux/sched/signal.h> 13 #include <linux/slab.h> 14 #include <linux/spinlock.h> 15 #include <linux/random.h> 16 #endif 17 18 #include "selftest.h" 19 20 #define CHAIN_SZ (4 << 10) 21 22 static inline struct mock_fence { 23 struct dma_fence base; 24 spinlock_t lock; 25 } *to_mock_fence(struct dma_fence *f) { 26 return container_of(f, struct mock_fence, base); 27 } 28 29 static const char *mock_name(struct dma_fence *f) 30 { 31 return "mock"; 32 } 33 34 static const struct dma_fence_ops mock_ops = { 35 .get_driver_name = mock_name, 36 .get_timeline_name = mock_name, 37 }; 38 39 static struct dma_fence *mock_fence(void) 40 { 41 struct mock_fence *f; 42 43 f = kmalloc(sizeof(*f), GFP_KERNEL); 44 if (!f) 45 return NULL; 46 47 spin_lock_init(&f->lock); 48 dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0); 49 50 return &f->base; 51 } 52 53 static struct dma_fence *mock_array(unsigned int num_fences, ...) 54 { 55 struct dma_fence_array *array; 56 struct dma_fence **fences; 57 va_list valist; 58 int i; 59 60 fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL); 61 if (!fences) 62 return NULL; 63 64 va_start(valist, num_fences); 65 for (i = 0; i < num_fences; ++i) 66 fences[i] = va_arg(valist, typeof(*fences)); 67 va_end(valist); 68 69 array = dma_fence_array_create(num_fences, fences, 70 dma_fence_context_alloc(1), 71 1, false); 72 if (!array) 73 goto cleanup; 74 return &array->base; 75 76 cleanup: 77 for (i = 0; i < num_fences; ++i) 78 dma_fence_put(fences[i]); 79 kfree(fences); 80 return NULL; 81 } 82 83 static struct dma_fence *mock_chain(struct dma_fence *prev, 84 struct dma_fence *fence) 85 { 86 struct dma_fence_chain *f; 87 88 f = dma_fence_chain_alloc(); 89 if (!f) { 90 dma_fence_put(prev); 91 dma_fence_put(fence); 92 return NULL; 93 } 94 95 dma_fence_chain_init(f, prev, fence, 1); 96 return &f->base; 97 } 98 99 static int sanitycheck(void *arg) 100 { 101 struct dma_fence *f, *chain, *array; 102 int err = 0; 103 104 f = mock_fence(); 105 if (!f) 106 return -ENOMEM; 107 108 array = mock_array(1, f); 109 if (!array) 110 return -ENOMEM; 111 112 chain = mock_chain(NULL, array); 113 if (!chain) 114 return -ENOMEM; 115 116 dma_fence_signal(f); 117 dma_fence_put(chain); 118 return err; 119 } 120 121 static int unwrap_array(void *arg) 122 { 123 struct dma_fence *fence, *f1, *f2, *array; 124 struct dma_fence_unwrap iter; 125 int err = 0; 126 127 f1 = mock_fence(); 128 if (!f1) 129 return -ENOMEM; 130 131 f2 = mock_fence(); 132 if (!f2) { 133 dma_fence_put(f1); 134 return -ENOMEM; 135 } 136 137 array = mock_array(2, f1, f2); 138 if (!array) 139 return -ENOMEM; 140 141 dma_fence_unwrap_for_each(fence, &iter, array) { 142 if (fence == f1) { 143 f1 = NULL; 144 } else if (fence == f2) { 145 f2 = NULL; 146 } else { 147 pr_err("Unexpected fence!\n"); 148 err = -EINVAL; 149 } 150 } 151 152 if (f1 || f2) { 153 pr_err("Not all fences seen!\n"); 154 err = -EINVAL; 155 } 156 157 dma_fence_signal(f1); 158 dma_fence_signal(f2); 159 dma_fence_put(array); 160 return 0; 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 f2 = mock_fence(); 174 if (!f2) { 175 dma_fence_put(f1); 176 return -ENOMEM; 177 } 178 179 chain = mock_chain(f1, f2); 180 if (!chain) 181 return -ENOMEM; 182 183 dma_fence_unwrap_for_each(fence, &iter, chain) { 184 if (fence == f1) { 185 f1 = NULL; 186 } else if (fence == f2) { 187 f2 = NULL; 188 } else { 189 pr_err("Unexpected fence!\n"); 190 err = -EINVAL; 191 } 192 } 193 194 if (f1 || f2) { 195 pr_err("Not all fences seen!\n"); 196 err = -EINVAL; 197 } 198 199 dma_fence_signal(f1); 200 dma_fence_signal(f2); 201 dma_fence_put(chain); 202 return 0; 203 } 204 205 static int unwrap_chain_array(void *arg) 206 { 207 struct dma_fence *fence, *f1, *f2, *array, *chain; 208 struct dma_fence_unwrap iter; 209 int err = 0; 210 211 f1 = mock_fence(); 212 if (!f1) 213 return -ENOMEM; 214 215 f2 = mock_fence(); 216 if (!f2) { 217 dma_fence_put(f1); 218 return -ENOMEM; 219 } 220 221 array = mock_array(2, f1, f2); 222 if (!array) 223 return -ENOMEM; 224 225 chain = mock_chain(NULL, array); 226 if (!chain) 227 return -ENOMEM; 228 229 dma_fence_unwrap_for_each(fence, &iter, chain) { 230 if (fence == f1) { 231 f1 = NULL; 232 } else if (fence == f2) { 233 f2 = NULL; 234 } else { 235 pr_err("Unexpected fence!\n"); 236 err = -EINVAL; 237 } 238 } 239 240 if (f1 || f2) { 241 pr_err("Not all fences seen!\n"); 242 err = -EINVAL; 243 } 244 245 dma_fence_signal(f1); 246 dma_fence_signal(f2); 247 dma_fence_put(chain); 248 return 0; 249 } 250 251 int dma_fence_unwrap(void) 252 { 253 static const struct subtest tests[] = { 254 SUBTEST(sanitycheck), 255 SUBTEST(unwrap_array), 256 SUBTEST(unwrap_chain), 257 SUBTEST(unwrap_chain_array), 258 }; 259 260 return subtests(tests, NULL); 261 } 262