1 /* SPDX-License-Identifier: MIT */ 2 3 /* 4 * Copyright © 2019 Intel Corporation 5 * Copyright © 2021 Advanced Micro Devices, Inc. 6 */ 7 8 #include <kunit/test.h> 9 #include <linux/slab.h> 10 #include <linux/spinlock.h> 11 #include <linux/dma-resv.h> 12 13 static DEFINE_SPINLOCK(fence_lock); 14 15 struct dma_resv_usage_param { 16 enum dma_resv_usage usage; 17 const char *desc; 18 }; 19 20 static const char *fence_name(struct dma_fence *f) 21 { 22 return "selftest"; 23 } 24 25 static const struct dma_fence_ops fence_ops = { 26 .get_driver_name = fence_name, 27 .get_timeline_name = fence_name, 28 }; 29 30 static struct dma_fence *alloc_fence(void) 31 { 32 struct dma_fence *f; 33 34 f = kmalloc_obj(*f); 35 if (!f) 36 return NULL; 37 38 dma_fence_init(f, &fence_ops, &fence_lock, 0, 0); 39 return f; 40 } 41 42 static void test_sanitycheck(struct kunit *test) 43 { 44 struct dma_resv resv; 45 struct dma_fence *f; 46 int r; 47 48 f = alloc_fence(); 49 KUNIT_ASSERT_NOT_NULL(test, f); 50 51 dma_fence_enable_sw_signaling(f); 52 53 dma_fence_signal(f); 54 dma_fence_put(f); 55 56 dma_resv_init(&resv); 57 r = dma_resv_lock(&resv, NULL); 58 if (r) 59 KUNIT_FAIL(test, "Resv locking failed\n"); 60 else 61 dma_resv_unlock(&resv); 62 dma_resv_fini(&resv); 63 } 64 65 static void test_signaling(struct kunit *test) 66 { 67 const struct dma_resv_usage_param *param = test->param_value; 68 enum dma_resv_usage usage = param->usage; 69 struct dma_resv resv; 70 struct dma_fence *f; 71 int r; 72 73 f = alloc_fence(); 74 KUNIT_ASSERT_NOT_NULL(test, f); 75 76 dma_fence_enable_sw_signaling(f); 77 78 dma_resv_init(&resv); 79 r = dma_resv_lock(&resv, NULL); 80 if (r) { 81 KUNIT_FAIL(test, "Resv locking failed"); 82 goto err_free; 83 } 84 85 r = dma_resv_reserve_fences(&resv, 1); 86 if (r) { 87 KUNIT_FAIL(test, "Resv shared slot allocation failed"); 88 goto err_unlock; 89 } 90 91 dma_resv_add_fence(&resv, f, usage); 92 if (dma_resv_test_signaled(&resv, usage)) { 93 KUNIT_FAIL(test, "Resv unexpectedly signaled"); 94 goto err_unlock; 95 } 96 dma_fence_signal(f); 97 if (!dma_resv_test_signaled(&resv, usage)) { 98 KUNIT_FAIL(test, "Resv not reporting signaled"); 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 } 107 108 static void test_for_each(struct kunit *test) 109 { 110 const struct dma_resv_usage_param *param = test->param_value; 111 enum dma_resv_usage usage = param->usage; 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 KUNIT_ASSERT_NOT_NULL(test, f); 119 120 dma_fence_enable_sw_signaling(f); 121 122 dma_resv_init(&resv); 123 r = dma_resv_lock(&resv, NULL); 124 if (r) { 125 KUNIT_FAIL(test, "Resv locking failed"); 126 goto err_free; 127 } 128 129 r = dma_resv_reserve_fences(&resv, 1); 130 if (r) { 131 KUNIT_FAIL(test, "Resv shared slot allocation failed"); 132 goto err_unlock; 133 } 134 135 dma_resv_add_fence(&resv, f, usage); 136 137 r = -ENOENT; 138 dma_resv_for_each_fence(&cursor, &resv, usage, fence) { 139 if (!r) { 140 KUNIT_FAIL(test, "More than one fence found"); 141 goto err_unlock; 142 } 143 if (f != fence) { 144 KUNIT_FAIL(test, "Unexpected fence"); 145 r = -EINVAL; 146 goto err_unlock; 147 } 148 if (dma_resv_iter_usage(&cursor) != usage) { 149 KUNIT_FAIL(test, "Unexpected fence usage"); 150 r = -EINVAL; 151 goto err_unlock; 152 } 153 r = 0; 154 } 155 if (r) { 156 KUNIT_FAIL(test, "No fence found"); 157 goto err_unlock; 158 } 159 dma_fence_signal(f); 160 err_unlock: 161 dma_resv_unlock(&resv); 162 err_free: 163 dma_resv_fini(&resv); 164 dma_fence_put(f); 165 } 166 167 static void test_for_each_unlocked(struct kunit *test) 168 { 169 const struct dma_resv_usage_param *param = test->param_value; 170 enum dma_resv_usage usage = param->usage; 171 struct dma_resv_iter cursor; 172 struct dma_fence *f, *fence; 173 struct dma_resv resv; 174 int r; 175 176 f = alloc_fence(); 177 KUNIT_ASSERT_NOT_NULL(test, f); 178 179 dma_fence_enable_sw_signaling(f); 180 181 dma_resv_init(&resv); 182 r = dma_resv_lock(&resv, NULL); 183 if (r) { 184 KUNIT_FAIL(test, "Resv locking failed"); 185 goto err_free; 186 } 187 188 r = dma_resv_reserve_fences(&resv, 1); 189 if (r) { 190 KUNIT_FAIL(test, "Resv shared slot allocation failed"); 191 dma_resv_unlock(&resv); 192 goto err_free; 193 } 194 195 dma_resv_add_fence(&resv, f, usage); 196 dma_resv_unlock(&resv); 197 198 r = -ENOENT; 199 dma_resv_iter_begin(&cursor, &resv, usage); 200 dma_resv_for_each_fence_unlocked(&cursor, fence) { 201 if (!r) { 202 KUNIT_FAIL(test, "More than one fence found"); 203 goto err_iter_end; 204 } 205 if (!dma_resv_iter_is_restarted(&cursor)) { 206 KUNIT_FAIL(test, "No restart flag"); 207 goto err_iter_end; 208 } 209 if (f != fence) { 210 KUNIT_FAIL(test, "Unexpected fence"); 211 r = -EINVAL; 212 goto err_iter_end; 213 } 214 if (dma_resv_iter_usage(&cursor) != usage) { 215 KUNIT_FAIL(test, "Unexpected fence usage"); 216 r = -EINVAL; 217 goto err_iter_end; 218 } 219 220 /* We use r as state here */ 221 if (r == -ENOENT) { 222 r = -EINVAL; 223 /* That should trigger an restart */ 224 cursor.fences = (void*)~0; 225 } else if (r == -EINVAL) { 226 r = 0; 227 } 228 } 229 KUNIT_EXPECT_EQ(test, r, 0); 230 err_iter_end: 231 dma_resv_iter_end(&cursor); 232 dma_fence_signal(f); 233 err_free: 234 dma_resv_fini(&resv); 235 dma_fence_put(f); 236 } 237 238 static void test_get_fences(struct kunit *test) 239 { 240 const struct dma_resv_usage_param *param = test->param_value; 241 enum dma_resv_usage usage = param->usage; 242 struct dma_fence *f, **fences = NULL; 243 struct dma_resv resv; 244 int r, i; 245 246 f = alloc_fence(); 247 KUNIT_ASSERT_NOT_NULL(test, f); 248 249 dma_fence_enable_sw_signaling(f); 250 251 dma_resv_init(&resv); 252 r = dma_resv_lock(&resv, NULL); 253 if (r) { 254 KUNIT_FAIL(test, "Resv locking failed"); 255 goto err_resv; 256 } 257 258 r = dma_resv_reserve_fences(&resv, 1); 259 if (r) { 260 KUNIT_FAIL(test, "Resv shared slot allocation failed"); 261 dma_resv_unlock(&resv); 262 goto err_resv; 263 } 264 265 dma_resv_add_fence(&resv, f, usage); 266 dma_resv_unlock(&resv); 267 268 r = dma_resv_get_fences(&resv, usage, &i, &fences); 269 if (r) { 270 KUNIT_FAIL(test, "get_fences failed"); 271 goto err_free; 272 } 273 274 if (i != 1 || fences[0] != f) { 275 KUNIT_FAIL(test, "get_fences returned unexpected fence"); 276 goto err_free; 277 } 278 279 dma_fence_signal(f); 280 err_free: 281 while (i--) 282 dma_fence_put(fences[i]); 283 kfree(fences); 284 err_resv: 285 dma_resv_fini(&resv); 286 dma_fence_put(f); 287 } 288 289 static const struct dma_resv_usage_param dma_resv_usage_params[] = { 290 { DMA_RESV_USAGE_KERNEL, "kernel" }, 291 { DMA_RESV_USAGE_WRITE, "write" }, 292 { DMA_RESV_USAGE_READ, "read" }, 293 { DMA_RESV_USAGE_BOOKKEEP, "bookkeep" }, 294 }; 295 296 KUNIT_ARRAY_PARAM_DESC(dma_resv_usage, dma_resv_usage_params, desc); 297 298 static struct kunit_case dma_resv_cases[] = { 299 KUNIT_CASE(test_sanitycheck), 300 KUNIT_CASE_PARAM(test_signaling, dma_resv_usage_gen_params), 301 KUNIT_CASE_PARAM(test_for_each, dma_resv_usage_gen_params), 302 KUNIT_CASE_PARAM(test_for_each_unlocked, dma_resv_usage_gen_params), 303 KUNIT_CASE_PARAM(test_get_fences, dma_resv_usage_gen_params), 304 {} 305 }; 306 307 static struct kunit_suite dma_resv_test_suite = { 308 .name = "dma-buf-resv", 309 .test_cases = dma_resv_cases, 310 }; 311 312 kunit_test_suite(dma_resv_test_suite); 313 314 MODULE_DESCRIPTION("KUnit tests for DMA-BUF"); 315 MODULE_LICENSE("GPL"); 316