Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: MIT */
0002 
0003 /*
0004 * Copyright © 2019 Intel Corporation
0005 * Copyright © 2021 Advanced Micro Devices, Inc.
0006 */
0007 
0008 #include <linux/slab.h>
0009 #include <linux/spinlock.h>
0010 #include <linux/dma-resv.h>
0011 
0012 #include "selftest.h"
0013 
0014 static struct spinlock fence_lock;
0015 
0016 static const char *fence_name(struct dma_fence *f)
0017 {
0018     return "selftest";
0019 }
0020 
0021 static const struct dma_fence_ops fence_ops = {
0022     .get_driver_name = fence_name,
0023     .get_timeline_name = fence_name,
0024 };
0025 
0026 static struct dma_fence *alloc_fence(void)
0027 {
0028     struct dma_fence *f;
0029 
0030     f = kmalloc(sizeof(*f), GFP_KERNEL);
0031     if (!f)
0032         return NULL;
0033 
0034     dma_fence_init(f, &fence_ops, &fence_lock, 0, 0);
0035     return f;
0036 }
0037 
0038 static int sanitycheck(void *arg)
0039 {
0040     struct dma_resv resv;
0041     struct dma_fence *f;
0042     int r;
0043 
0044     f = alloc_fence();
0045     if (!f)
0046         return -ENOMEM;
0047 
0048     dma_fence_signal(f);
0049     dma_fence_put(f);
0050 
0051     dma_resv_init(&resv);
0052     r = dma_resv_lock(&resv, NULL);
0053     if (r)
0054         pr_err("Resv locking failed\n");
0055     else
0056         dma_resv_unlock(&resv);
0057     dma_resv_fini(&resv);
0058     return r;
0059 }
0060 
0061 static int test_signaling(void *arg)
0062 {
0063     enum dma_resv_usage usage = (unsigned long)arg;
0064     struct dma_resv resv;
0065     struct dma_fence *f;
0066     int r;
0067 
0068     f = alloc_fence();
0069     if (!f)
0070         return -ENOMEM;
0071 
0072     dma_resv_init(&resv);
0073     r = dma_resv_lock(&resv, NULL);
0074     if (r) {
0075         pr_err("Resv locking failed\n");
0076         goto err_free;
0077     }
0078 
0079     r = dma_resv_reserve_fences(&resv, 1);
0080     if (r) {
0081         pr_err("Resv shared slot allocation failed\n");
0082         goto err_unlock;
0083     }
0084 
0085     dma_resv_add_fence(&resv, f, usage);
0086     if (dma_resv_test_signaled(&resv, usage)) {
0087         pr_err("Resv unexpectedly signaled\n");
0088         r = -EINVAL;
0089         goto err_unlock;
0090     }
0091     dma_fence_signal(f);
0092     if (!dma_resv_test_signaled(&resv, usage)) {
0093         pr_err("Resv not reporting signaled\n");
0094         r = -EINVAL;
0095         goto err_unlock;
0096     }
0097 err_unlock:
0098     dma_resv_unlock(&resv);
0099 err_free:
0100     dma_resv_fini(&resv);
0101     dma_fence_put(f);
0102     return r;
0103 }
0104 
0105 static int test_for_each(void *arg)
0106 {
0107     enum dma_resv_usage usage = (unsigned long)arg;
0108     struct dma_resv_iter cursor;
0109     struct dma_fence *f, *fence;
0110     struct dma_resv resv;
0111     int r;
0112 
0113     f = alloc_fence();
0114     if (!f)
0115         return -ENOMEM;
0116 
0117     dma_resv_init(&resv);
0118     r = dma_resv_lock(&resv, NULL);
0119     if (r) {
0120         pr_err("Resv locking failed\n");
0121         goto err_free;
0122     }
0123 
0124     r = dma_resv_reserve_fences(&resv, 1);
0125     if (r) {
0126         pr_err("Resv shared slot allocation failed\n");
0127         goto err_unlock;
0128     }
0129 
0130     dma_resv_add_fence(&resv, f, usage);
0131 
0132     r = -ENOENT;
0133     dma_resv_for_each_fence(&cursor, &resv, usage, fence) {
0134         if (!r) {
0135             pr_err("More than one fence found\n");
0136             r = -EINVAL;
0137             goto err_unlock;
0138         }
0139         if (f != fence) {
0140             pr_err("Unexpected fence\n");
0141             r = -EINVAL;
0142             goto err_unlock;
0143         }
0144         if (dma_resv_iter_usage(&cursor) != usage) {
0145             pr_err("Unexpected fence usage\n");
0146             r = -EINVAL;
0147             goto err_unlock;
0148         }
0149         r = 0;
0150     }
0151     if (r) {
0152         pr_err("No fence found\n");
0153         goto err_unlock;
0154     }
0155     dma_fence_signal(f);
0156 err_unlock:
0157     dma_resv_unlock(&resv);
0158 err_free:
0159     dma_resv_fini(&resv);
0160     dma_fence_put(f);
0161     return r;
0162 }
0163 
0164 static int test_for_each_unlocked(void *arg)
0165 {
0166     enum dma_resv_usage usage = (unsigned long)arg;
0167     struct dma_resv_iter cursor;
0168     struct dma_fence *f, *fence;
0169     struct dma_resv resv;
0170     int r;
0171 
0172     f = alloc_fence();
0173     if (!f)
0174         return -ENOMEM;
0175 
0176     dma_resv_init(&resv);
0177     r = dma_resv_lock(&resv, NULL);
0178     if (r) {
0179         pr_err("Resv locking failed\n");
0180         goto err_free;
0181     }
0182 
0183     r = dma_resv_reserve_fences(&resv, 1);
0184     if (r) {
0185         pr_err("Resv shared slot allocation failed\n");
0186         dma_resv_unlock(&resv);
0187         goto err_free;
0188     }
0189 
0190     dma_resv_add_fence(&resv, f, usage);
0191     dma_resv_unlock(&resv);
0192 
0193     r = -ENOENT;
0194     dma_resv_iter_begin(&cursor, &resv, usage);
0195     dma_resv_for_each_fence_unlocked(&cursor, fence) {
0196         if (!r) {
0197             pr_err("More than one fence found\n");
0198             r = -EINVAL;
0199             goto err_iter_end;
0200         }
0201         if (!dma_resv_iter_is_restarted(&cursor)) {
0202             pr_err("No restart flag\n");
0203             goto err_iter_end;
0204         }
0205         if (f != fence) {
0206             pr_err("Unexpected fence\n");
0207             r = -EINVAL;
0208             goto err_iter_end;
0209         }
0210         if (dma_resv_iter_usage(&cursor) != usage) {
0211             pr_err("Unexpected fence usage\n");
0212             r = -EINVAL;
0213             goto err_iter_end;
0214         }
0215 
0216         /* We use r as state here */
0217         if (r == -ENOENT) {
0218             r = -EINVAL;
0219             /* That should trigger an restart */
0220             cursor.fences = (void*)~0;
0221         } else if (r == -EINVAL) {
0222             r = 0;
0223         }
0224     }
0225     if (r)
0226         pr_err("No fence found\n");
0227 err_iter_end:
0228     dma_resv_iter_end(&cursor);
0229     dma_fence_signal(f);
0230 err_free:
0231     dma_resv_fini(&resv);
0232     dma_fence_put(f);
0233     return r;
0234 }
0235 
0236 static int test_get_fences(void *arg)
0237 {
0238     enum dma_resv_usage usage = (unsigned long)arg;
0239     struct dma_fence *f, **fences = NULL;
0240     struct dma_resv resv;
0241     int r, i;
0242 
0243     f = alloc_fence();
0244     if (!f)
0245         return -ENOMEM;
0246 
0247     dma_resv_init(&resv);
0248     r = dma_resv_lock(&resv, NULL);
0249     if (r) {
0250         pr_err("Resv locking failed\n");
0251         goto err_resv;
0252     }
0253 
0254     r = dma_resv_reserve_fences(&resv, 1);
0255     if (r) {
0256         pr_err("Resv shared slot allocation failed\n");
0257         dma_resv_unlock(&resv);
0258         goto err_resv;
0259     }
0260 
0261     dma_resv_add_fence(&resv, f, usage);
0262     dma_resv_unlock(&resv);
0263 
0264     r = dma_resv_get_fences(&resv, usage, &i, &fences);
0265     if (r) {
0266         pr_err("get_fences failed\n");
0267         goto err_free;
0268     }
0269 
0270     if (i != 1 || fences[0] != f) {
0271         pr_err("get_fences returned unexpected fence\n");
0272         goto err_free;
0273     }
0274 
0275     dma_fence_signal(f);
0276 err_free:
0277     while (i--)
0278         dma_fence_put(fences[i]);
0279     kfree(fences);
0280 err_resv:
0281     dma_resv_fini(&resv);
0282     dma_fence_put(f);
0283     return r;
0284 }
0285 
0286 int dma_resv(void)
0287 {
0288     static const struct subtest tests[] = {
0289         SUBTEST(sanitycheck),
0290         SUBTEST(test_signaling),
0291         SUBTEST(test_for_each),
0292         SUBTEST(test_for_each_unlocked),
0293         SUBTEST(test_get_fences),
0294     };
0295     enum dma_resv_usage usage;
0296     int r;
0297 
0298     spin_lock_init(&fence_lock);
0299     for (usage = DMA_RESV_USAGE_KERNEL; usage <= DMA_RESV_USAGE_BOOKKEEP;
0300          ++usage) {
0301         r = subtests(tests, (void *)(unsigned long)usage);
0302         if (r)
0303             return r;
0304     }
0305     return 0;
0306 }