Merge drm-misc/drm-misc-next-fixes into drm-misc-fixes
There were a few patches left in drm-misc-next-fixes, let's bring them into drm-misc-fixes. Signed-off-by: Maxime Ripard <maxime@cerno.tech>
This commit is contained in:
commit
13043d1a12
@ -185,6 +185,12 @@ DMA Fence Chain
|
|||||||
.. kernel-doc:: include/linux/dma-fence-chain.h
|
.. kernel-doc:: include/linux/dma-fence-chain.h
|
||||||
:internal:
|
:internal:
|
||||||
|
|
||||||
|
DMA Fence unwrap
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/dma-fence-unwrap.h
|
||||||
|
:internal:
|
||||||
|
|
||||||
DMA Fence uABI/Sync File
|
DMA Fence uABI/Sync File
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ dmabuf_selftests-y := \
|
|||||||
selftest.o \
|
selftest.o \
|
||||||
st-dma-fence.o \
|
st-dma-fence.o \
|
||||||
st-dma-fence-chain.o \
|
st-dma-fence-chain.o \
|
||||||
|
st-dma-fence-unwrap.o \
|
||||||
st-dma-resv.o
|
st-dma-resv.o
|
||||||
|
|
||||||
obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o
|
obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o
|
||||||
|
@ -159,6 +159,8 @@ struct dma_fence_array *dma_fence_array_create(int num_fences,
|
|||||||
struct dma_fence_array *array;
|
struct dma_fence_array *array;
|
||||||
size_t size = sizeof(*array);
|
size_t size = sizeof(*array);
|
||||||
|
|
||||||
|
WARN_ON(!num_fences || !fences);
|
||||||
|
|
||||||
/* Allocate the callback structures behind the array. */
|
/* Allocate the callback structures behind the array. */
|
||||||
size += num_fences * sizeof(struct dma_fence_array_cb);
|
size += num_fences * sizeof(struct dma_fence_array_cb);
|
||||||
array = kzalloc(size, GFP_KERNEL);
|
array = kzalloc(size, GFP_KERNEL);
|
||||||
@ -219,3 +221,33 @@ bool dma_fence_match_context(struct dma_fence *fence, u64 context)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dma_fence_match_context);
|
EXPORT_SYMBOL(dma_fence_match_context);
|
||||||
|
|
||||||
|
struct dma_fence *dma_fence_array_first(struct dma_fence *head)
|
||||||
|
{
|
||||||
|
struct dma_fence_array *array;
|
||||||
|
|
||||||
|
if (!head)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
array = to_dma_fence_array(head);
|
||||||
|
if (!array)
|
||||||
|
return head;
|
||||||
|
|
||||||
|
if (!array->num_fences)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return array->fences[0];
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(dma_fence_array_first);
|
||||||
|
|
||||||
|
struct dma_fence *dma_fence_array_next(struct dma_fence *head,
|
||||||
|
unsigned int index)
|
||||||
|
{
|
||||||
|
struct dma_fence_array *array = to_dma_fence_array(head);
|
||||||
|
|
||||||
|
if (!array || index >= array->num_fences)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return array->fences[index];
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(dma_fence_array_next);
|
||||||
|
@ -12,4 +12,5 @@
|
|||||||
selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */
|
selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */
|
||||||
selftest(dma_fence, dma_fence)
|
selftest(dma_fence, dma_fence)
|
||||||
selftest(dma_fence_chain, dma_fence_chain)
|
selftest(dma_fence_chain, dma_fence_chain)
|
||||||
|
selftest(dma_fence_unwrap, dma_fence_unwrap)
|
||||||
selftest(dma_resv, dma_resv)
|
selftest(dma_resv, dma_resv)
|
||||||
|
261
drivers/dma-buf/st-dma-fence-unwrap.c
Normal file
261
drivers/dma-buf/st-dma-fence-unwrap.c
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Advanced Micro Devices, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/dma-fence-unwrap.h>
|
||||||
|
#if 0
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/kthread.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
#include <linux/sched/signal.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/random.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "selftest.h"
|
||||||
|
|
||||||
|
#define CHAIN_SZ (4 << 10)
|
||||||
|
|
||||||
|
static inline struct mock_fence {
|
||||||
|
struct dma_fence base;
|
||||||
|
spinlock_t lock;
|
||||||
|
} *to_mock_fence(struct dma_fence *f) {
|
||||||
|
return container_of(f, struct mock_fence, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *mock_name(struct dma_fence *f)
|
||||||
|
{
|
||||||
|
return "mock";
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct dma_fence_ops mock_ops = {
|
||||||
|
.get_driver_name = mock_name,
|
||||||
|
.get_timeline_name = mock_name,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct dma_fence *mock_fence(void)
|
||||||
|
{
|
||||||
|
struct mock_fence *f;
|
||||||
|
|
||||||
|
f = kmalloc(sizeof(*f), GFP_KERNEL);
|
||||||
|
if (!f)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
spin_lock_init(&f->lock);
|
||||||
|
dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
|
||||||
|
|
||||||
|
return &f->base;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct dma_fence *mock_array(unsigned int num_fences, ...)
|
||||||
|
{
|
||||||
|
struct dma_fence_array *array;
|
||||||
|
struct dma_fence **fences;
|
||||||
|
va_list valist;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
|
||||||
|
if (!fences)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
va_start(valist, num_fences);
|
||||||
|
for (i = 0; i < num_fences; ++i)
|
||||||
|
fences[i] = va_arg(valist, typeof(*fences));
|
||||||
|
va_end(valist);
|
||||||
|
|
||||||
|
array = dma_fence_array_create(num_fences, fences,
|
||||||
|
dma_fence_context_alloc(1),
|
||||||
|
1, false);
|
||||||
|
if (!array)
|
||||||
|
goto cleanup;
|
||||||
|
return &array->base;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
for (i = 0; i < num_fences; ++i)
|
||||||
|
dma_fence_put(fences[i]);
|
||||||
|
kfree(fences);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct dma_fence *mock_chain(struct dma_fence *prev,
|
||||||
|
struct dma_fence *fence)
|
||||||
|
{
|
||||||
|
struct dma_fence_chain *f;
|
||||||
|
|
||||||
|
f = dma_fence_chain_alloc();
|
||||||
|
if (!f) {
|
||||||
|
dma_fence_put(prev);
|
||||||
|
dma_fence_put(fence);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dma_fence_chain_init(f, prev, fence, 1);
|
||||||
|
return &f->base;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sanitycheck(void *arg)
|
||||||
|
{
|
||||||
|
struct dma_fence *f, *chain, *array;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
f = mock_fence();
|
||||||
|
if (!f)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
array = mock_array(1, f);
|
||||||
|
if (!array)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
chain = mock_chain(NULL, array);
|
||||||
|
if (!chain)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
dma_fence_signal(f);
|
||||||
|
dma_fence_put(chain);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int unwrap_array(void *arg)
|
||||||
|
{
|
||||||
|
struct dma_fence *fence, *f1, *f2, *array;
|
||||||
|
struct dma_fence_unwrap iter;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
f1 = mock_fence();
|
||||||
|
if (!f1)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
f2 = mock_fence();
|
||||||
|
if (!f2) {
|
||||||
|
dma_fence_put(f1);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
array = mock_array(2, f1, f2);
|
||||||
|
if (!array)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
dma_fence_unwrap_for_each(fence, &iter, array) {
|
||||||
|
if (fence == f1) {
|
||||||
|
f1 = NULL;
|
||||||
|
} else if (fence == f2) {
|
||||||
|
f2 = NULL;
|
||||||
|
} else {
|
||||||
|
pr_err("Unexpected fence!\n");
|
||||||
|
err = -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f1 || f2) {
|
||||||
|
pr_err("Not all fences seen!\n");
|
||||||
|
err = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dma_fence_signal(f1);
|
||||||
|
dma_fence_signal(f2);
|
||||||
|
dma_fence_put(array);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int unwrap_chain(void *arg)
|
||||||
|
{
|
||||||
|
struct dma_fence *fence, *f1, *f2, *chain;
|
||||||
|
struct dma_fence_unwrap iter;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
f1 = mock_fence();
|
||||||
|
if (!f1)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
f2 = mock_fence();
|
||||||
|
if (!f2) {
|
||||||
|
dma_fence_put(f1);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
chain = mock_chain(f1, f2);
|
||||||
|
if (!chain)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
dma_fence_unwrap_for_each(fence, &iter, chain) {
|
||||||
|
if (fence == f1) {
|
||||||
|
f1 = NULL;
|
||||||
|
} else if (fence == f2) {
|
||||||
|
f2 = NULL;
|
||||||
|
} else {
|
||||||
|
pr_err("Unexpected fence!\n");
|
||||||
|
err = -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f1 || f2) {
|
||||||
|
pr_err("Not all fences seen!\n");
|
||||||
|
err = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dma_fence_signal(f1);
|
||||||
|
dma_fence_signal(f2);
|
||||||
|
dma_fence_put(chain);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int unwrap_chain_array(void *arg)
|
||||||
|
{
|
||||||
|
struct dma_fence *fence, *f1, *f2, *array, *chain;
|
||||||
|
struct dma_fence_unwrap iter;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
f1 = mock_fence();
|
||||||
|
if (!f1)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
f2 = mock_fence();
|
||||||
|
if (!f2) {
|
||||||
|
dma_fence_put(f1);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
array = mock_array(2, f1, f2);
|
||||||
|
if (!array)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
chain = mock_chain(NULL, array);
|
||||||
|
if (!chain)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
dma_fence_unwrap_for_each(fence, &iter, chain) {
|
||||||
|
if (fence == f1) {
|
||||||
|
f1 = NULL;
|
||||||
|
} else if (fence == f2) {
|
||||||
|
f2 = NULL;
|
||||||
|
} else {
|
||||||
|
pr_err("Unexpected fence!\n");
|
||||||
|
err = -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f1 || f2) {
|
||||||
|
pr_err("Not all fences seen!\n");
|
||||||
|
err = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dma_fence_signal(f1);
|
||||||
|
dma_fence_signal(f2);
|
||||||
|
dma_fence_put(chain);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dma_fence_unwrap(void)
|
||||||
|
{
|
||||||
|
static const struct subtest tests[] = {
|
||||||
|
SUBTEST(sanitycheck),
|
||||||
|
SUBTEST(unwrap_array),
|
||||||
|
SUBTEST(unwrap_chain),
|
||||||
|
SUBTEST(unwrap_chain_array),
|
||||||
|
};
|
||||||
|
|
||||||
|
return subtests(tests, NULL);
|
||||||
|
}
|
@ -5,6 +5,7 @@
|
|||||||
* Copyright (C) 2012 Google, Inc.
|
* Copyright (C) 2012 Google, Inc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/dma-fence-unwrap.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <linux/file.h>
|
#include <linux/file.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
@ -172,20 +173,6 @@ static int sync_file_set_fence(struct sync_file *sync_file,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct dma_fence **get_fences(struct sync_file *sync_file,
|
|
||||||
int *num_fences)
|
|
||||||
{
|
|
||||||
if (dma_fence_is_array(sync_file->fence)) {
|
|
||||||
struct dma_fence_array *array = to_dma_fence_array(sync_file->fence);
|
|
||||||
|
|
||||||
*num_fences = array->num_fences;
|
|
||||||
return array->fences;
|
|
||||||
}
|
|
||||||
|
|
||||||
*num_fences = 1;
|
|
||||||
return &sync_file->fence;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_fence(struct dma_fence **fences,
|
static void add_fence(struct dma_fence **fences,
|
||||||
int *i, struct dma_fence *fence)
|
int *i, struct dma_fence *fence)
|
||||||
{
|
{
|
||||||
@ -210,86 +197,97 @@ static void add_fence(struct dma_fence **fences,
|
|||||||
static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
|
static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
|
||||||
struct sync_file *b)
|
struct sync_file *b)
|
||||||
{
|
{
|
||||||
|
struct dma_fence *a_fence, *b_fence, **fences;
|
||||||
|
struct dma_fence_unwrap a_iter, b_iter;
|
||||||
|
unsigned int index, num_fences;
|
||||||
struct sync_file *sync_file;
|
struct sync_file *sync_file;
|
||||||
struct dma_fence **fences = NULL, **nfences, **a_fences, **b_fences;
|
|
||||||
int i = 0, i_a, i_b, num_fences, a_num_fences, b_num_fences;
|
|
||||||
|
|
||||||
sync_file = sync_file_alloc();
|
sync_file = sync_file_alloc();
|
||||||
if (!sync_file)
|
if (!sync_file)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
a_fences = get_fences(a, &a_num_fences);
|
num_fences = 0;
|
||||||
b_fences = get_fences(b, &b_num_fences);
|
dma_fence_unwrap_for_each(a_fence, &a_iter, a->fence)
|
||||||
if (a_num_fences > INT_MAX - b_num_fences)
|
++num_fences;
|
||||||
goto err;
|
dma_fence_unwrap_for_each(b_fence, &b_iter, b->fence)
|
||||||
|
++num_fences;
|
||||||
|
|
||||||
num_fences = a_num_fences + b_num_fences;
|
if (num_fences > INT_MAX)
|
||||||
|
goto err_free_sync_file;
|
||||||
|
|
||||||
fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
|
fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
|
||||||
if (!fences)
|
if (!fences)
|
||||||
goto err;
|
goto err_free_sync_file;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Assume sync_file a and b are both ordered and have no
|
* We can't guarantee that fences in both a and b are ordered, but it is
|
||||||
* duplicates with the same context.
|
* still quite likely.
|
||||||
*
|
*
|
||||||
* If a sync_file can only be created with sync_file_merge
|
* So attempt to order the fences as we pass over them and merge fences
|
||||||
* and sync_file_create, this is a reasonable assumption.
|
* with the same context.
|
||||||
*/
|
*/
|
||||||
for (i_a = i_b = 0; i_a < a_num_fences && i_b < b_num_fences; ) {
|
|
||||||
struct dma_fence *pt_a = a_fences[i_a];
|
|
||||||
struct dma_fence *pt_b = b_fences[i_b];
|
|
||||||
|
|
||||||
if (pt_a->context < pt_b->context) {
|
index = 0;
|
||||||
add_fence(fences, &i, pt_a);
|
for (a_fence = dma_fence_unwrap_first(a->fence, &a_iter),
|
||||||
|
b_fence = dma_fence_unwrap_first(b->fence, &b_iter);
|
||||||
|
a_fence || b_fence; ) {
|
||||||
|
|
||||||
i_a++;
|
if (!b_fence) {
|
||||||
} else if (pt_a->context > pt_b->context) {
|
add_fence(fences, &index, a_fence);
|
||||||
add_fence(fences, &i, pt_b);
|
a_fence = dma_fence_unwrap_next(&a_iter);
|
||||||
|
|
||||||
|
} else if (!a_fence) {
|
||||||
|
add_fence(fences, &index, b_fence);
|
||||||
|
b_fence = dma_fence_unwrap_next(&b_iter);
|
||||||
|
|
||||||
|
} else if (a_fence->context < b_fence->context) {
|
||||||
|
add_fence(fences, &index, a_fence);
|
||||||
|
a_fence = dma_fence_unwrap_next(&a_iter);
|
||||||
|
|
||||||
|
} else if (b_fence->context < a_fence->context) {
|
||||||
|
add_fence(fences, &index, b_fence);
|
||||||
|
b_fence = dma_fence_unwrap_next(&b_iter);
|
||||||
|
|
||||||
|
} else if (__dma_fence_is_later(a_fence->seqno, b_fence->seqno,
|
||||||
|
a_fence->ops)) {
|
||||||
|
add_fence(fences, &index, a_fence);
|
||||||
|
a_fence = dma_fence_unwrap_next(&a_iter);
|
||||||
|
b_fence = dma_fence_unwrap_next(&b_iter);
|
||||||
|
|
||||||
i_b++;
|
|
||||||
} else {
|
} else {
|
||||||
if (__dma_fence_is_later(pt_a->seqno, pt_b->seqno,
|
add_fence(fences, &index, b_fence);
|
||||||
pt_a->ops))
|
a_fence = dma_fence_unwrap_next(&a_iter);
|
||||||
add_fence(fences, &i, pt_a);
|
b_fence = dma_fence_unwrap_next(&b_iter);
|
||||||
else
|
|
||||||
add_fence(fences, &i, pt_b);
|
|
||||||
|
|
||||||
i_a++;
|
|
||||||
i_b++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; i_a < a_num_fences; i_a++)
|
if (index == 0)
|
||||||
add_fence(fences, &i, a_fences[i_a]);
|
fences[index++] = dma_fence_get_stub();
|
||||||
|
|
||||||
for (; i_b < b_num_fences; i_b++)
|
if (num_fences > index) {
|
||||||
add_fence(fences, &i, b_fences[i_b]);
|
struct dma_fence **tmp;
|
||||||
|
|
||||||
if (i == 0)
|
/* Keep going even when reducing the size failed */
|
||||||
fences[i++] = dma_fence_get(a_fences[0]);
|
tmp = krealloc_array(fences, index, sizeof(*fences),
|
||||||
|
GFP_KERNEL);
|
||||||
if (num_fences > i) {
|
if (tmp)
|
||||||
nfences = krealloc_array(fences, i, sizeof(*fences), GFP_KERNEL);
|
fences = tmp;
|
||||||
if (!nfences)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
fences = nfences;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sync_file_set_fence(sync_file, fences, i) < 0)
|
if (sync_file_set_fence(sync_file, fences, index) < 0)
|
||||||
goto err;
|
goto err_put_fences;
|
||||||
|
|
||||||
strlcpy(sync_file->user_name, name, sizeof(sync_file->user_name));
|
strlcpy(sync_file->user_name, name, sizeof(sync_file->user_name));
|
||||||
return sync_file;
|
return sync_file;
|
||||||
|
|
||||||
err:
|
err_put_fences:
|
||||||
while (i)
|
while (index)
|
||||||
dma_fence_put(fences[--i]);
|
dma_fence_put(fences[--index]);
|
||||||
kfree(fences);
|
kfree(fences);
|
||||||
|
|
||||||
|
err_free_sync_file:
|
||||||
fput(sync_file->file);
|
fput(sync_file->file);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sync_file_release(struct inode *inode, struct file *file)
|
static int sync_file_release(struct inode *inode, struct file *file)
|
||||||
@ -398,11 +396,13 @@ static int sync_fill_fence_info(struct dma_fence *fence,
|
|||||||
static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
|
static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
|
||||||
unsigned long arg)
|
unsigned long arg)
|
||||||
{
|
{
|
||||||
struct sync_file_info info;
|
|
||||||
struct sync_fence_info *fence_info = NULL;
|
struct sync_fence_info *fence_info = NULL;
|
||||||
struct dma_fence **fences;
|
struct dma_fence_unwrap iter;
|
||||||
|
struct sync_file_info info;
|
||||||
|
unsigned int num_fences;
|
||||||
|
struct dma_fence *fence;
|
||||||
|
int ret;
|
||||||
__u32 size;
|
__u32 size;
|
||||||
int num_fences, ret, i;
|
|
||||||
|
|
||||||
if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
|
if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
@ -410,7 +410,9 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
|
|||||||
if (info.flags || info.pad)
|
if (info.flags || info.pad)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
fences = get_fences(sync_file, &num_fences);
|
num_fences = 0;
|
||||||
|
dma_fence_unwrap_for_each(fence, &iter, sync_file->fence)
|
||||||
|
++num_fences;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Passing num_fences = 0 means that userspace doesn't want to
|
* Passing num_fences = 0 means that userspace doesn't want to
|
||||||
@ -433,8 +435,11 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
|
|||||||
if (!fence_info)
|
if (!fence_info)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
for (i = 0; i < num_fences; i++) {
|
num_fences = 0;
|
||||||
int status = sync_fill_fence_info(fences[i], &fence_info[i]);
|
dma_fence_unwrap_for_each(fence, &iter, sync_file->fence) {
|
||||||
|
int status;
|
||||||
|
|
||||||
|
status = sync_fill_fence_info(fence, &fence_info[num_fences++]);
|
||||||
info.status = info.status <= 0 ? info.status : status;
|
info.status = info.status <= 0 ? info.status : status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,6 +214,29 @@ int drm_of_encoder_active_endpoint(struct device_node *node,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(drm_of_encoder_active_endpoint);
|
EXPORT_SYMBOL_GPL(drm_of_encoder_active_endpoint);
|
||||||
|
|
||||||
|
static int find_panel_or_bridge(struct device_node *node,
|
||||||
|
struct drm_panel **panel,
|
||||||
|
struct drm_bridge **bridge)
|
||||||
|
{
|
||||||
|
if (panel) {
|
||||||
|
*panel = of_drm_find_panel(node);
|
||||||
|
if (!IS_ERR(*panel))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Clear the panel pointer in case of error. */
|
||||||
|
*panel = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No panel found yet, check for a bridge next. */
|
||||||
|
if (bridge) {
|
||||||
|
*bridge = of_drm_find_bridge(node);
|
||||||
|
if (*bridge)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EPROBE_DEFER;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* drm_of_find_panel_or_bridge - return connected panel or bridge device
|
* drm_of_find_panel_or_bridge - return connected panel or bridge device
|
||||||
* @np: device tree node containing encoder output ports
|
* @np: device tree node containing encoder output ports
|
||||||
@ -236,66 +259,44 @@ int drm_of_find_panel_or_bridge(const struct device_node *np,
|
|||||||
struct drm_panel **panel,
|
struct drm_panel **panel,
|
||||||
struct drm_bridge **bridge)
|
struct drm_bridge **bridge)
|
||||||
{
|
{
|
||||||
int ret = -EPROBE_DEFER;
|
struct device_node *node;
|
||||||
struct device_node *remote;
|
int ret;
|
||||||
|
|
||||||
if (!panel && !bridge)
|
if (!panel && !bridge)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (panel)
|
if (panel)
|
||||||
*panel = NULL;
|
*panel = NULL;
|
||||||
|
if (bridge)
|
||||||
|
*bridge = NULL;
|
||||||
|
|
||||||
/**
|
/* Check for a graph on the device node first. */
|
||||||
* Devices can also be child nodes when we also control that device
|
if (of_graph_is_present(np)) {
|
||||||
* through the upstream device (ie, MIPI-DCS for a MIPI-DSI device).
|
node = of_graph_get_remote_node(np, port, endpoint);
|
||||||
*
|
if (node) {
|
||||||
* Lookup for a child node of the given parent that isn't either port
|
ret = find_panel_or_bridge(node, panel, bridge);
|
||||||
* or ports.
|
of_node_put(node);
|
||||||
*/
|
|
||||||
for_each_available_child_of_node(np, remote) {
|
if (!ret)
|
||||||
if (of_node_name_eq(remote, "port") ||
|
return 0;
|
||||||
of_node_name_eq(remote, "ports"))
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise check for any child node other than port/ports. */
|
||||||
|
for_each_available_child_of_node(np, node) {
|
||||||
|
if (of_node_name_eq(node, "port") ||
|
||||||
|
of_node_name_eq(node, "ports"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
goto of_find_panel_or_bridge;
|
ret = find_panel_or_bridge(node, panel, bridge);
|
||||||
|
of_node_put(node);
|
||||||
|
|
||||||
|
/* Stop at the first found occurrence. */
|
||||||
|
if (!ret)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
return -EPROBE_DEFER;
|
||||||
* of_graph_get_remote_node() produces a noisy error message if port
|
|
||||||
* node isn't found and the absence of the port is a legit case here,
|
|
||||||
* so at first we silently check whether graph presents in the
|
|
||||||
* device-tree node.
|
|
||||||
*/
|
|
||||||
if (!of_graph_is_present(np))
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
remote = of_graph_get_remote_node(np, port, endpoint);
|
|
||||||
|
|
||||||
of_find_panel_or_bridge:
|
|
||||||
if (!remote)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
if (panel) {
|
|
||||||
*panel = of_drm_find_panel(remote);
|
|
||||||
if (!IS_ERR(*panel))
|
|
||||||
ret = 0;
|
|
||||||
else
|
|
||||||
*panel = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* No panel found yet, check for a bridge next. */
|
|
||||||
if (bridge) {
|
|
||||||
if (ret) {
|
|
||||||
*bridge = of_drm_find_bridge(remote);
|
|
||||||
if (*bridge)
|
|
||||||
ret = 0;
|
|
||||||
} else {
|
|
||||||
*bridge = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
of_node_put(remote);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(drm_of_find_panel_or_bridge);
|
EXPORT_SYMBOL_GPL(drm_of_find_panel_or_bridge);
|
||||||
|
|
||||||
|
@ -61,6 +61,21 @@ to_dma_fence_array(struct dma_fence *fence)
|
|||||||
return container_of(fence, struct dma_fence_array, base);
|
return container_of(fence, struct dma_fence_array, base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dma_fence_array_for_each - iterate over all fences in array
|
||||||
|
* @fence: current fence
|
||||||
|
* @index: index into the array
|
||||||
|
* @head: potential dma_fence_array object
|
||||||
|
*
|
||||||
|
* Test if @array is a dma_fence_array object and if yes iterate over all fences
|
||||||
|
* in the array. If not just iterate over the fence in @array itself.
|
||||||
|
*
|
||||||
|
* For a deep dive iterator see dma_fence_unwrap_for_each().
|
||||||
|
*/
|
||||||
|
#define dma_fence_array_for_each(fence, index, head) \
|
||||||
|
for (index = 0, fence = dma_fence_array_first(head); fence; \
|
||||||
|
++(index), fence = dma_fence_array_next(head, index))
|
||||||
|
|
||||||
struct dma_fence_array *dma_fence_array_create(int num_fences,
|
struct dma_fence_array *dma_fence_array_create(int num_fences,
|
||||||
struct dma_fence **fences,
|
struct dma_fence **fences,
|
||||||
u64 context, unsigned seqno,
|
u64 context, unsigned seqno,
|
||||||
@ -68,4 +83,8 @@ struct dma_fence_array *dma_fence_array_create(int num_fences,
|
|||||||
|
|
||||||
bool dma_fence_match_context(struct dma_fence *fence, u64 context);
|
bool dma_fence_match_context(struct dma_fence *fence, u64 context);
|
||||||
|
|
||||||
|
struct dma_fence *dma_fence_array_first(struct dma_fence *head);
|
||||||
|
struct dma_fence *dma_fence_array_next(struct dma_fence *head,
|
||||||
|
unsigned int index);
|
||||||
|
|
||||||
#endif /* __LINUX_DMA_FENCE_ARRAY_H */
|
#endif /* __LINUX_DMA_FENCE_ARRAY_H */
|
||||||
|
@ -112,6 +112,8 @@ static inline void dma_fence_chain_free(struct dma_fence_chain *chain)
|
|||||||
*
|
*
|
||||||
* Iterate over all fences in the chain. We keep a reference to the current
|
* Iterate over all fences in the chain. We keep a reference to the current
|
||||||
* fence while inside the loop which must be dropped when breaking out.
|
* fence while inside the loop which must be dropped when breaking out.
|
||||||
|
*
|
||||||
|
* For a deep dive iterator see dma_fence_unwrap_for_each().
|
||||||
*/
|
*/
|
||||||
#define dma_fence_chain_for_each(iter, head) \
|
#define dma_fence_chain_for_each(iter, head) \
|
||||||
for (iter = dma_fence_get(head); iter; \
|
for (iter = dma_fence_get(head); iter; \
|
||||||
|
95
include/linux/dma-fence-unwrap.h
Normal file
95
include/linux/dma-fence-unwrap.h
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
|
/*
|
||||||
|
* fence-chain: chain fences together in a timeline
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 Advanced Micro Devices, Inc.
|
||||||
|
* Authors:
|
||||||
|
* Christian König <christian.koenig@amd.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LINUX_DMA_FENCE_UNWRAP_H
|
||||||
|
#define __LINUX_DMA_FENCE_UNWRAP_H
|
||||||
|
|
||||||
|
#include <linux/dma-fence-chain.h>
|
||||||
|
#include <linux/dma-fence-array.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct dma_fence_unwrap - cursor into the container structure
|
||||||
|
*
|
||||||
|
* Should be used with dma_fence_unwrap_for_each() iterator macro.
|
||||||
|
*/
|
||||||
|
struct dma_fence_unwrap {
|
||||||
|
/**
|
||||||
|
* @chain: potential dma_fence_chain, but can be other fence as well
|
||||||
|
*/
|
||||||
|
struct dma_fence *chain;
|
||||||
|
/**
|
||||||
|
* @array: potential dma_fence_array, but can be other fence as well
|
||||||
|
*/
|
||||||
|
struct dma_fence *array;
|
||||||
|
/**
|
||||||
|
* @index: last returned index if @array is really a dma_fence_array
|
||||||
|
*/
|
||||||
|
unsigned int index;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Internal helper to start new array iteration, don't use directly */
|
||||||
|
static inline struct dma_fence *
|
||||||
|
__dma_fence_unwrap_array(struct dma_fence_unwrap * cursor)
|
||||||
|
{
|
||||||
|
cursor->array = dma_fence_chain_contained(cursor->chain);
|
||||||
|
cursor->index = 0;
|
||||||
|
return dma_fence_array_first(cursor->array);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dma_fence_unwrap_first - return the first fence from fence containers
|
||||||
|
* @head: the entrypoint into the containers
|
||||||
|
* @cursor: current position inside the containers
|
||||||
|
*
|
||||||
|
* Unwraps potential dma_fence_chain/dma_fence_array containers and return the
|
||||||
|
* first fence.
|
||||||
|
*/
|
||||||
|
static inline struct dma_fence *
|
||||||
|
dma_fence_unwrap_first(struct dma_fence *head, struct dma_fence_unwrap *cursor)
|
||||||
|
{
|
||||||
|
cursor->chain = dma_fence_get(head);
|
||||||
|
return __dma_fence_unwrap_array(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dma_fence_unwrap_next - return the next fence from a fence containers
|
||||||
|
* @cursor: current position inside the containers
|
||||||
|
*
|
||||||
|
* Continue unwrapping the dma_fence_chain/dma_fence_array containers and return
|
||||||
|
* the next fence from them.
|
||||||
|
*/
|
||||||
|
static inline struct dma_fence *
|
||||||
|
dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
|
||||||
|
{
|
||||||
|
struct dma_fence *tmp;
|
||||||
|
|
||||||
|
++cursor->index;
|
||||||
|
tmp = dma_fence_array_next(cursor->array, cursor->index);
|
||||||
|
if (tmp)
|
||||||
|
return tmp;
|
||||||
|
|
||||||
|
cursor->chain = dma_fence_chain_walk(cursor->chain);
|
||||||
|
return __dma_fence_unwrap_array(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dma_fence_unwrap_for_each - iterate over all fences in containers
|
||||||
|
* @fence: current fence
|
||||||
|
* @cursor: current position inside the containers
|
||||||
|
* @head: starting point for the iterator
|
||||||
|
*
|
||||||
|
* Unwrap dma_fence_chain and dma_fence_array containers and deep dive into all
|
||||||
|
* potential fences in them. If @head is just a normal fence only that one is
|
||||||
|
* returned.
|
||||||
|
*/
|
||||||
|
#define dma_fence_unwrap_for_each(fence, cursor, head) \
|
||||||
|
for (fence = dma_fence_unwrap_first(head, cursor); fence; \
|
||||||
|
fence = dma_fence_unwrap_next(cursor))
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user