cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

st-dma-resv.c (5782B)


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