mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 00:29:35 +08:00
This was done entirely with mindless brute force, using
git grep -l '\<k[vmz]*alloc_objs*(.*, GFP_KERNEL)' |
xargs sed -i 's/\(alloc_objs*(.*\), GFP_KERNEL)/\1)/'
to convert the new alloc_obj() users that had a simple GFP_KERNEL
argument to just drop that argument.
Note that due to the extreme simplicity of the scripting, any slightly
more complex cases spread over multiple lines would not be triggered:
they definitely exist, but this covers the vast bulk of the cases, and
the resulting diff is also then easier to check automatically.
For the same reason the 'flex' versions will be done as a separate
conversion.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
317 lines
5.8 KiB
C
317 lines
5.8 KiB
C
/* SPDX-License-Identifier: MIT */
|
|
|
|
/*
|
|
* Copyright © 2019 Intel Corporation
|
|
* Copyright © 2021 Advanced Micro Devices, Inc.
|
|
*/
|
|
|
|
#include <linux/slab.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/dma-resv.h>
|
|
|
|
#include "selftest.h"
|
|
|
|
static struct spinlock fence_lock;
|
|
|
|
static const char *fence_name(struct dma_fence *f)
|
|
{
|
|
return "selftest";
|
|
}
|
|
|
|
static const struct dma_fence_ops fence_ops = {
|
|
.get_driver_name = fence_name,
|
|
.get_timeline_name = fence_name,
|
|
};
|
|
|
|
static struct dma_fence *alloc_fence(void)
|
|
{
|
|
struct dma_fence *f;
|
|
|
|
f = kmalloc_obj(*f);
|
|
if (!f)
|
|
return NULL;
|
|
|
|
dma_fence_init(f, &fence_ops, &fence_lock, 0, 0);
|
|
return f;
|
|
}
|
|
|
|
static int sanitycheck(void *arg)
|
|
{
|
|
struct dma_resv resv;
|
|
struct dma_fence *f;
|
|
int r;
|
|
|
|
f = alloc_fence();
|
|
if (!f)
|
|
return -ENOMEM;
|
|
|
|
dma_fence_enable_sw_signaling(f);
|
|
|
|
dma_fence_signal(f);
|
|
dma_fence_put(f);
|
|
|
|
dma_resv_init(&resv);
|
|
r = dma_resv_lock(&resv, NULL);
|
|
if (r)
|
|
pr_err("Resv locking failed\n");
|
|
else
|
|
dma_resv_unlock(&resv);
|
|
dma_resv_fini(&resv);
|
|
return r;
|
|
}
|
|
|
|
static int test_signaling(void *arg)
|
|
{
|
|
enum dma_resv_usage usage = (unsigned long)arg;
|
|
struct dma_resv resv;
|
|
struct dma_fence *f;
|
|
int r;
|
|
|
|
f = alloc_fence();
|
|
if (!f)
|
|
return -ENOMEM;
|
|
|
|
dma_fence_enable_sw_signaling(f);
|
|
|
|
dma_resv_init(&resv);
|
|
r = dma_resv_lock(&resv, NULL);
|
|
if (r) {
|
|
pr_err("Resv locking failed\n");
|
|
goto err_free;
|
|
}
|
|
|
|
r = dma_resv_reserve_fences(&resv, 1);
|
|
if (r) {
|
|
pr_err("Resv shared slot allocation failed\n");
|
|
goto err_unlock;
|
|
}
|
|
|
|
dma_resv_add_fence(&resv, f, usage);
|
|
if (dma_resv_test_signaled(&resv, usage)) {
|
|
pr_err("Resv unexpectedly signaled\n");
|
|
r = -EINVAL;
|
|
goto err_unlock;
|
|
}
|
|
dma_fence_signal(f);
|
|
if (!dma_resv_test_signaled(&resv, usage)) {
|
|
pr_err("Resv not reporting signaled\n");
|
|
r = -EINVAL;
|
|
goto err_unlock;
|
|
}
|
|
err_unlock:
|
|
dma_resv_unlock(&resv);
|
|
err_free:
|
|
dma_resv_fini(&resv);
|
|
dma_fence_put(f);
|
|
return r;
|
|
}
|
|
|
|
static int test_for_each(void *arg)
|
|
{
|
|
enum dma_resv_usage usage = (unsigned long)arg;
|
|
struct dma_resv_iter cursor;
|
|
struct dma_fence *f, *fence;
|
|
struct dma_resv resv;
|
|
int r;
|
|
|
|
f = alloc_fence();
|
|
if (!f)
|
|
return -ENOMEM;
|
|
|
|
dma_fence_enable_sw_signaling(f);
|
|
|
|
dma_resv_init(&resv);
|
|
r = dma_resv_lock(&resv, NULL);
|
|
if (r) {
|
|
pr_err("Resv locking failed\n");
|
|
goto err_free;
|
|
}
|
|
|
|
r = dma_resv_reserve_fences(&resv, 1);
|
|
if (r) {
|
|
pr_err("Resv shared slot allocation failed\n");
|
|
goto err_unlock;
|
|
}
|
|
|
|
dma_resv_add_fence(&resv, f, usage);
|
|
|
|
r = -ENOENT;
|
|
dma_resv_for_each_fence(&cursor, &resv, usage, fence) {
|
|
if (!r) {
|
|
pr_err("More than one fence found\n");
|
|
r = -EINVAL;
|
|
goto err_unlock;
|
|
}
|
|
if (f != fence) {
|
|
pr_err("Unexpected fence\n");
|
|
r = -EINVAL;
|
|
goto err_unlock;
|
|
}
|
|
if (dma_resv_iter_usage(&cursor) != usage) {
|
|
pr_err("Unexpected fence usage\n");
|
|
r = -EINVAL;
|
|
goto err_unlock;
|
|
}
|
|
r = 0;
|
|
}
|
|
if (r) {
|
|
pr_err("No fence found\n");
|
|
goto err_unlock;
|
|
}
|
|
dma_fence_signal(f);
|
|
err_unlock:
|
|
dma_resv_unlock(&resv);
|
|
err_free:
|
|
dma_resv_fini(&resv);
|
|
dma_fence_put(f);
|
|
return r;
|
|
}
|
|
|
|
static int test_for_each_unlocked(void *arg)
|
|
{
|
|
enum dma_resv_usage usage = (unsigned long)arg;
|
|
struct dma_resv_iter cursor;
|
|
struct dma_fence *f, *fence;
|
|
struct dma_resv resv;
|
|
int r;
|
|
|
|
f = alloc_fence();
|
|
if (!f)
|
|
return -ENOMEM;
|
|
|
|
dma_fence_enable_sw_signaling(f);
|
|
|
|
dma_resv_init(&resv);
|
|
r = dma_resv_lock(&resv, NULL);
|
|
if (r) {
|
|
pr_err("Resv locking failed\n");
|
|
goto err_free;
|
|
}
|
|
|
|
r = dma_resv_reserve_fences(&resv, 1);
|
|
if (r) {
|
|
pr_err("Resv shared slot allocation failed\n");
|
|
dma_resv_unlock(&resv);
|
|
goto err_free;
|
|
}
|
|
|
|
dma_resv_add_fence(&resv, f, usage);
|
|
dma_resv_unlock(&resv);
|
|
|
|
r = -ENOENT;
|
|
dma_resv_iter_begin(&cursor, &resv, usage);
|
|
dma_resv_for_each_fence_unlocked(&cursor, fence) {
|
|
if (!r) {
|
|
pr_err("More than one fence found\n");
|
|
r = -EINVAL;
|
|
goto err_iter_end;
|
|
}
|
|
if (!dma_resv_iter_is_restarted(&cursor)) {
|
|
pr_err("No restart flag\n");
|
|
goto err_iter_end;
|
|
}
|
|
if (f != fence) {
|
|
pr_err("Unexpected fence\n");
|
|
r = -EINVAL;
|
|
goto err_iter_end;
|
|
}
|
|
if (dma_resv_iter_usage(&cursor) != usage) {
|
|
pr_err("Unexpected fence usage\n");
|
|
r = -EINVAL;
|
|
goto err_iter_end;
|
|
}
|
|
|
|
/* We use r as state here */
|
|
if (r == -ENOENT) {
|
|
r = -EINVAL;
|
|
/* That should trigger an restart */
|
|
cursor.fences = (void*)~0;
|
|
} else if (r == -EINVAL) {
|
|
r = 0;
|
|
}
|
|
}
|
|
if (r)
|
|
pr_err("No fence found\n");
|
|
err_iter_end:
|
|
dma_resv_iter_end(&cursor);
|
|
dma_fence_signal(f);
|
|
err_free:
|
|
dma_resv_fini(&resv);
|
|
dma_fence_put(f);
|
|
return r;
|
|
}
|
|
|
|
static int test_get_fences(void *arg)
|
|
{
|
|
enum dma_resv_usage usage = (unsigned long)arg;
|
|
struct dma_fence *f, **fences = NULL;
|
|
struct dma_resv resv;
|
|
int r, i;
|
|
|
|
f = alloc_fence();
|
|
if (!f)
|
|
return -ENOMEM;
|
|
|
|
dma_fence_enable_sw_signaling(f);
|
|
|
|
dma_resv_init(&resv);
|
|
r = dma_resv_lock(&resv, NULL);
|
|
if (r) {
|
|
pr_err("Resv locking failed\n");
|
|
goto err_resv;
|
|
}
|
|
|
|
r = dma_resv_reserve_fences(&resv, 1);
|
|
if (r) {
|
|
pr_err("Resv shared slot allocation failed\n");
|
|
dma_resv_unlock(&resv);
|
|
goto err_resv;
|
|
}
|
|
|
|
dma_resv_add_fence(&resv, f, usage);
|
|
dma_resv_unlock(&resv);
|
|
|
|
r = dma_resv_get_fences(&resv, usage, &i, &fences);
|
|
if (r) {
|
|
pr_err("get_fences failed\n");
|
|
goto err_free;
|
|
}
|
|
|
|
if (i != 1 || fences[0] != f) {
|
|
pr_err("get_fences returned unexpected fence\n");
|
|
goto err_free;
|
|
}
|
|
|
|
dma_fence_signal(f);
|
|
err_free:
|
|
while (i--)
|
|
dma_fence_put(fences[i]);
|
|
kfree(fences);
|
|
err_resv:
|
|
dma_resv_fini(&resv);
|
|
dma_fence_put(f);
|
|
return r;
|
|
}
|
|
|
|
int dma_resv(void)
|
|
{
|
|
static const struct subtest tests[] = {
|
|
SUBTEST(sanitycheck),
|
|
SUBTEST(test_signaling),
|
|
SUBTEST(test_for_each),
|
|
SUBTEST(test_for_each_unlocked),
|
|
SUBTEST(test_get_fences),
|
|
};
|
|
enum dma_resv_usage usage;
|
|
int r;
|
|
|
|
spin_lock_init(&fence_lock);
|
|
for (usage = DMA_RESV_USAGE_KERNEL; usage <= DMA_RESV_USAGE_BOOKKEEP;
|
|
++usage) {
|
|
r = subtests(tests, (void *)(unsigned long)usage);
|
|
if (r)
|
|
return r;
|
|
}
|
|
return 0;
|
|
}
|