drm-misc-next-fixes for v5.18-rc2:
- fix warning about fence containers - fix logic error in new fence merge code - handle empty dma_fence_arrays gracefully - Try all possible cases for bridge/panel detection. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEuXvWqAysSYEJGuVH/lWMcqZwE8MFAmJOwqsACgkQ/lWMcqZw E8NdAw//YQB9FuU3x0JmUCa4SY63mnNyQXUz2ZRe6DV39nSOqrGV0QlZr538/oJk HfSyAOs+zLYsZSvZNmQ4zgSlyU/IcAR68lB1wVgcVHn3XKPq0Dxxd0kOg9aQ5Hpd xF2wIxeMmHj5BJWe+S6IIWdCyWMRneT9R5lFLI59S08A3yGAY2x4u+8G+YpH1bZa cfxOfpHWCbgwCbjpjcVFd1JQAo9EcqHlebvNqpZzf5RPYIVaYRQrx+p0e1u6rjxc EVRube1dxhx13O1k4EGA4ghornl8uDpvaYU09L83xUHgYDehO7XmlwN2YCZZE09Y ZA2OVJ9Hh3RSYa8bQQ5AXlKddcYkmWJa7Zvvi1u6CVBW7pNNPYm8ryMXppIqMW2q 2Lmc5LsZnNCHshgjQz9L5P4IBZh1EQ97ti4efRLvx4DSCMyBmBSHVicfs8m0HhlO jNPmmJJjMxWzTtx1UvI3fmSFxKsSYBC4eTa/ihspFmuGT0U5+WdPDFEGn1NrykCX nAHn0ldfJUfBgYis7kk1qNH4hqNH7EsLu7SH68jqCAdxMhz4pzk54VDSFX/qtmUx tP+4Z71/jMV5di3l27rftCgUBfnX3Q9KJoRIx02J87QgsPjiCwOBIWTC4viKk8cq JBkRH+U8LhmqUDwaKvOsNsO/ReNm+seWU6s2aELnLOB2KLDiIJk= =MY3d -----END PGP SIGNATURE----- Merge tag 'drm-misc-next-fixes-2022-04-07' of git://anongit.freedesktop.org/drm/drm-misc into drm-fixes drm-misc-next-fixes for v5.18-rc2: - fix warning about fence containers - fix logic error in new fence merge code - handle empty dma_fence_arrays gracefully - Try all possible cases for bridge/panel detection. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/3b8e6439-612e-f640-e380-51e834393e94@linux.intel.com
This commit is contained in:
commit
995f748073
|
@ -185,6 +185,12 @@ DMA Fence Chain
|
|||
.. kernel-doc:: include/linux/dma-fence-chain.h
|
||||
:internal:
|
||||
|
||||
DMA Fence unwrap
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
.. kernel-doc:: include/linux/dma-fence-unwrap.h
|
||||
:internal:
|
||||
|
||||
DMA Fence uABI/Sync File
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ dmabuf_selftests-y := \
|
|||
selftest.o \
|
||||
st-dma-fence.o \
|
||||
st-dma-fence-chain.o \
|
||||
st-dma-fence-unwrap.o \
|
||||
st-dma-resv.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;
|
||||
size_t size = sizeof(*array);
|
||||
|
||||
WARN_ON(!num_fences || !fences);
|
||||
|
||||
/* Allocate the callback structures behind the array. */
|
||||
size += num_fences * sizeof(struct dma_fence_array_cb);
|
||||
array = kzalloc(size, GFP_KERNEL);
|
||||
|
@ -219,3 +221,33 @@ bool dma_fence_match_context(struct dma_fence *fence, u64 context)
|
|||
return true;
|
||||
}
|
||||
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(dma_fence, dma_fence)
|
||||
selftest(dma_fence_chain, dma_fence_chain)
|
||||
selftest(dma_fence_unwrap, dma_fence_unwrap)
|
||||
selftest(dma_resv, dma_resv)
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
||||
#include <linux/dma-fence-unwrap.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/fs.h>
|
||||
|
@ -172,20 +173,6 @@ static int sync_file_set_fence(struct sync_file *sync_file,
|
|||
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,
|
||||
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,
|
||||
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 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();
|
||||
if (!sync_file)
|
||||
return NULL;
|
||||
|
||||
a_fences = get_fences(a, &a_num_fences);
|
||||
b_fences = get_fences(b, &b_num_fences);
|
||||
if (a_num_fences > INT_MAX - b_num_fences)
|
||||
goto err;
|
||||
num_fences = 0;
|
||||
dma_fence_unwrap_for_each(a_fence, &a_iter, a->fence)
|
||||
++num_fences;
|
||||
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);
|
||||
if (!fences)
|
||||
goto err;
|
||||
goto err_free_sync_file;
|
||||
|
||||
/*
|
||||
* Assume sync_file a and b are both ordered and have no
|
||||
* duplicates with the same context.
|
||||
* We can't guarantee that fences in both a and b are ordered, but it is
|
||||
* still quite likely.
|
||||
*
|
||||
* If a sync_file can only be created with sync_file_merge
|
||||
* and sync_file_create, this is a reasonable assumption.
|
||||
* So attempt to order the fences as we pass over them and merge fences
|
||||
* 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) {
|
||||
add_fence(fences, &i, pt_a);
|
||||
index = 0;
|
||||
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++;
|
||||
} else if (pt_a->context > pt_b->context) {
|
||||
add_fence(fences, &i, pt_b);
|
||||
if (!b_fence) {
|
||||
add_fence(fences, &index, a_fence);
|
||||
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 {
|
||||
if (__dma_fence_is_later(pt_a->seqno, pt_b->seqno,
|
||||
pt_a->ops))
|
||||
add_fence(fences, &i, pt_a);
|
||||
else
|
||||
add_fence(fences, &i, pt_b);
|
||||
|
||||
i_a++;
|
||||
i_b++;
|
||||
add_fence(fences, &index, b_fence);
|
||||
a_fence = dma_fence_unwrap_next(&a_iter);
|
||||
b_fence = dma_fence_unwrap_next(&b_iter);
|
||||
}
|
||||
}
|
||||
|
||||
for (; i_a < a_num_fences; i_a++)
|
||||
add_fence(fences, &i, a_fences[i_a]);
|
||||
if (index == 0)
|
||||
fences[index++] = dma_fence_get_stub();
|
||||
|
||||
for (; i_b < b_num_fences; i_b++)
|
||||
add_fence(fences, &i, b_fences[i_b]);
|
||||
if (num_fences > index) {
|
||||
struct dma_fence **tmp;
|
||||
|
||||
if (i == 0)
|
||||
fences[i++] = dma_fence_get(a_fences[0]);
|
||||
|
||||
if (num_fences > i) {
|
||||
nfences = krealloc_array(fences, i, sizeof(*fences), GFP_KERNEL);
|
||||
if (!nfences)
|
||||
goto err;
|
||||
|
||||
fences = nfences;
|
||||
/* Keep going even when reducing the size failed */
|
||||
tmp = krealloc_array(fences, index, sizeof(*fences),
|
||||
GFP_KERNEL);
|
||||
if (tmp)
|
||||
fences = tmp;
|
||||
}
|
||||
|
||||
if (sync_file_set_fence(sync_file, fences, i) < 0)
|
||||
goto err;
|
||||
if (sync_file_set_fence(sync_file, fences, index) < 0)
|
||||
goto err_put_fences;
|
||||
|
||||
strlcpy(sync_file->user_name, name, sizeof(sync_file->user_name));
|
||||
return sync_file;
|
||||
|
||||
err:
|
||||
while (i)
|
||||
dma_fence_put(fences[--i]);
|
||||
err_put_fences:
|
||||
while (index)
|
||||
dma_fence_put(fences[--index]);
|
||||
kfree(fences);
|
||||
|
||||
err_free_sync_file:
|
||||
fput(sync_file->file);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
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,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct sync_file_info info;
|
||||
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;
|
||||
int num_fences, ret, i;
|
||||
|
||||
if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
|
||||
return -EFAULT;
|
||||
|
@ -410,7 +410,9 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
|
|||
if (info.flags || info.pad)
|
||||
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
|
||||
|
@ -433,8 +435,11 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
|
|||
if (!fence_info)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < num_fences; i++) {
|
||||
int status = sync_fill_fence_info(fences[i], &fence_info[i]);
|
||||
num_fences = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -214,6 +214,29 @@ int drm_of_encoder_active_endpoint(struct device_node *node,
|
|||
}
|
||||
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
|
||||
* @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_bridge **bridge)
|
||||
{
|
||||
int ret = -EPROBE_DEFER;
|
||||
struct device_node *remote;
|
||||
struct device_node *node;
|
||||
int ret;
|
||||
|
||||
if (!panel && !bridge)
|
||||
return -EINVAL;
|
||||
|
||||
if (panel)
|
||||
*panel = NULL;
|
||||
if (bridge)
|
||||
*bridge = NULL;
|
||||
|
||||
/**
|
||||
* Devices can also be child nodes when we also control that device
|
||||
* through the upstream device (ie, MIPI-DCS for a MIPI-DSI device).
|
||||
*
|
||||
* Lookup for a child node of the given parent that isn't either port
|
||||
* or ports.
|
||||
*/
|
||||
for_each_available_child_of_node(np, remote) {
|
||||
if (of_node_name_eq(remote, "port") ||
|
||||
of_node_name_eq(remote, "ports"))
|
||||
/* Check for a graph on the device node first. */
|
||||
if (of_graph_is_present(np)) {
|
||||
node = of_graph_get_remote_node(np, port, endpoint);
|
||||
if (node) {
|
||||
ret = find_panel_or_bridge(node, panel, bridge);
|
||||
of_node_put(node);
|
||||
|
||||
if (!ret)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 **fences,
|
||||
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);
|
||||
|
||||
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 */
|
||||
|
|
|
@ -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
|
||||
* 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) \
|
||||
for (iter = dma_fence_get(head); iter; \
|
||||
|
|
|
@ -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