From: "Christian König" <christian.koenig@amd.com>
To: "Daniel Vetter" <daniel@ffwll.ch>,
"Christian König" <ckoenig.leichtzumerken@gmail.com>
Cc: sumit.semwal@linaro.org, gustavo@padovan.org,
daniel.vetter@ffwll.ch, linux-media@vger.kernel.org,
dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org
Subject: Re: [PATCH 3/3] dma-buf: generalize fence merging
Date: Wed, 4 May 2022 10:52:20 +0200 [thread overview]
Message-ID: <09d1cd03-1da0-bb7a-5770-a75de67dffc8@amd.com> (raw)
In-Reply-To: <YnI8qJbJ1DYklNcm@phenom.ffwll.local>
Am 04.05.22 um 10:43 schrieb Daniel Vetter:
> On Tue, Apr 26, 2022 at 02:46:37PM +0200, Christian König wrote:
>> Introduce a dma_fence_merge() macro which allows to unwrap fences which
>> potentially can be containers as well and then merge them back together
>> into a flat dma_fence_array.
>>
>> Signed-off-by: Christian König <christian.koenig@amd.com>
> So this is really neat (the va args macro trick especially), but I'm not
> sure how much use it is with just one user. Is there like more planned?
We have another potential user of this in drm_syncobj_flatten_chain()
and at least another potential cases in amdgpu come to my mind.
I just wanted to double check the general implementation before I start
to use this more widely.
> Or is the idea to make merging consistent so that the context sorting
> trick can be done consistently?
The context sorting trick is just a nice to have optimization. My main
intention here is to have an utility function for flattening things out
I can point people to which does the job and works reliable in all cases.
Christian.
> -Daniel
>
>> ---
>> drivers/dma-buf/dma-fence-unwrap.c | 95 ++++++++++++++++++++
>> drivers/dma-buf/st-dma-fence-unwrap.c | 47 ++++++++++
>> drivers/dma-buf/sync_file.c | 119 ++------------------------
>> include/linux/dma-fence-unwrap.h | 24 ++++++
>> 4 files changed, 172 insertions(+), 113 deletions(-)
>>
>> diff --git a/drivers/dma-buf/dma-fence-unwrap.c b/drivers/dma-buf/dma-fence-unwrap.c
>> index 711be125428c..c9becc74896d 100644
>> --- a/drivers/dma-buf/dma-fence-unwrap.c
>> +++ b/drivers/dma-buf/dma-fence-unwrap.c
>> @@ -11,6 +11,7 @@
>> #include <linux/dma-fence-array.h>
>> #include <linux/dma-fence-chain.h>
>> #include <linux/dma-fence-unwrap.h>
>> +#include <linux/slab.h>
>>
>> /* Internal helper to start new array iteration, don't use directly */
>> static struct dma_fence *
>> @@ -57,3 +58,97 @@ struct dma_fence *dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
>> return __dma_fence_unwrap_array(cursor);
>> }
>> EXPORT_SYMBOL_GPL(dma_fence_unwrap_next);
>> +
>> +/* Implementation for the dma_fence_merge() marco, don't use directly */
>> +struct dma_fence *__dma_fence_merge(unsigned int num_fences,
>> + struct dma_fence **fences,
>> + struct dma_fence_unwrap *iter)
>> +{
>> + struct dma_fence_array *result;
>> + struct dma_fence *tmp, **array;
>> + unsigned int i, count;
>> +
>> + count = 0;
>> + for (i = 0; i < num_fences; ++i) {
>> + dma_fence_unwrap_for_each(tmp, &iter[i], fences[i])
>> + if (!dma_fence_is_signaled(tmp))
>> + ++count;
>> + }
>> +
>> + if (count == 0)
>> + return dma_fence_get_stub();
>> +
>> + if (count > INT_MAX)
>> + return NULL;
>> +
>> + array = kmalloc_array(count, sizeof(*array), GFP_KERNEL);
>> + if (!array)
>> + return NULL;
>> +
>> + /*
>> + * We can't guarantee that inpute fences are ordered by context, but
>> + * it is still quite likely when this function is used multiple times.
>> + * So attempt to order the fences by context as we pass over them and
>> + * merge fences with the same context.
>> + */
>> + for (i = 0; i < num_fences; ++i)
>> + fences[i] = dma_fence_unwrap_first(fences[i], &iter[i]);
>> +
>> + count = 0;
>> + do {
>> + unsigned int sel;
>> +
>> +restart:
>> + tmp = NULL;
>> + for (i = 0; i < num_fences; ++i) {
>> + struct dma_fence *next = fences[i];
>> +
>> + if (!next || dma_fence_is_signaled(next))
>> + continue;
>> +
>> + if (!tmp || tmp->context > next->context) {
>> + tmp = next;
>> + sel = i;
>> +
>> + } else if (tmp->context < next->context) {
>> + continue;
>> +
>> + } else if (dma_fence_is_later(tmp, next)) {
>> + fences[i] = dma_fence_unwrap_next(&iter[i]);
>> + goto restart;
>> + } else {
>> + fences[sel] = dma_fence_unwrap_next(&iter[sel]);
>> + goto restart;
>> + }
>> + }
>> +
>> + if (tmp) {
>> + array[count++] = dma_fence_get(tmp);
>> + fences[sel] = dma_fence_unwrap_next(&iter[sel]);
>> + }
>> + } while (tmp);
>> +
>> + if (count == 0) {
>> + tmp = dma_fence_get_stub();
>> + goto return_tmp;
>> + }
>> +
>> + if (count == 1) {
>> + tmp = array[0];
>> + goto return_tmp;
>> + }
>> +
>> + result = dma_fence_array_create(count, array,
>> + dma_fence_context_alloc(1),
>> + 1, false);
>> + if (!result) {
>> + tmp = NULL;
>> + goto return_tmp;
>> + }
>> + return &result->base;
>> +
>> +return_tmp:
>> + kfree(array);
>> + return tmp;
>> +}
>> +EXPORT_SYMBOL_GPL(__dma_fence_merge);
>> diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c
>> index 59628add93f5..23ab134417ed 100644
>> --- a/drivers/dma-buf/st-dma-fence-unwrap.c
>> +++ b/drivers/dma-buf/st-dma-fence-unwrap.c
>> @@ -240,6 +240,52 @@ static int unwrap_chain_array(void *arg)
>> return err;
>> }
>>
>> +static int unwrap_merge(void *arg)
>> +{
>> + struct dma_fence *fence, *f1, *f2, *f3;
>> + struct dma_fence_unwrap iter;
>> + int err = 0;
>> +
>> + f1 = mock_fence();
>> + if (!f1)
>> + return -ENOMEM;
>> +
>> + f2 = mock_fence();
>> + if (!f2) {
>> + err = -ENOMEM;
>> + goto error_put_f1;
>> + }
>> +
>> + f3 = dma_fence_merge(f1, f2);
>> + if (!f3) {
>> + err = -ENOMEM;
>> + goto error_put_f2;
>> + }
>> +
>> + dma_fence_unwrap_for_each(fence, &iter, f3) {
>> + 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_put(f3);
>> +error_put_f2:
>> + dma_fence_put(f2);
>> +error_put_f1:
>> + dma_fence_put(f1);
>> + return err;
>> +}
>> +
>> int dma_fence_unwrap(void)
>> {
>> static const struct subtest tests[] = {
>> @@ -247,6 +293,7 @@ int dma_fence_unwrap(void)
>> SUBTEST(unwrap_array),
>> SUBTEST(unwrap_chain),
>> SUBTEST(unwrap_chain_array),
>> + SUBTEST(unwrap_merge),
>> };
>>
>> return subtests(tests, NULL);
>> diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c
>> index 0fe564539166..fe149d7e3ce2 100644
>> --- a/drivers/dma-buf/sync_file.c
>> +++ b/drivers/dma-buf/sync_file.c
>> @@ -146,50 +146,6 @@ char *sync_file_get_name(struct sync_file *sync_file, char *buf, int len)
>> return buf;
>> }
>>
>> -static int sync_file_set_fence(struct sync_file *sync_file,
>> - struct dma_fence **fences, int num_fences)
>> -{
>> - struct dma_fence_array *array;
>> -
>> - /*
>> - * The reference for the fences in the new sync_file and held
>> - * in add_fence() during the merge procedure, so for num_fences == 1
>> - * we already own a new reference to the fence. For num_fence > 1
>> - * we own the reference of the dma_fence_array creation.
>> - */
>> -
>> - if (num_fences == 0) {
>> - sync_file->fence = dma_fence_get_stub();
>> - kfree(fences);
>> -
>> - } else if (num_fences == 1) {
>> - sync_file->fence = fences[0];
>> - kfree(fences);
>> -
>> - } else {
>> - array = dma_fence_array_create(num_fences, fences,
>> - dma_fence_context_alloc(1),
>> - 1, false);
>> - if (!array)
>> - return -ENOMEM;
>> -
>> - sync_file->fence = &array->base;
>> - }
>> -
>> - return 0;
>> -}
>> -
>> -static void add_fence(struct dma_fence **fences,
>> - int *i, struct dma_fence *fence)
>> -{
>> - fences[*i] = fence;
>> -
>> - if (!dma_fence_is_signaled(fence)) {
>> - dma_fence_get(fence);
>> - (*i)++;
>> - }
>> -}
>> -
>> /**
>> * sync_file_merge() - merge two sync_files
>> * @name: name of new fence
>> @@ -203,84 +159,21 @@ 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 *fence;
>>
>> sync_file = sync_file_alloc();
>> if (!sync_file)
>> return NULL;
>>
>> - 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;
>> -
>> - if (num_fences > INT_MAX)
>> - goto err_free_sync_file;
>> -
>> - fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
>> - if (!fences)
>> - goto err_free_sync_file;
>> -
>> - /*
>> - * We can't guarantee that fences in both a and b are ordered, but it is
>> - * still quite likely.
>> - *
>> - * So attempt to order the fences as we pass over them and merge fences
>> - * with the same context.
>> - */
>> -
>> - 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; ) {
>> -
>> - 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);
>> -
>> - } else {
>> - add_fence(fences, &index, b_fence);
>> - a_fence = dma_fence_unwrap_next(&a_iter);
>> - b_fence = dma_fence_unwrap_next(&b_iter);
>> - }
>> + fence = dma_fence_merge(a->fence, b->fence);
>> + if (!fence) {
>> + fput(sync_file->file);
>> + return NULL;
>> }
>> -
>> - if (sync_file_set_fence(sync_file, fences, index) < 0)
>> - goto err_put_fences;
>> -
>> + sync_file->fence = fence;
>> strlcpy(sync_file->user_name, name, sizeof(sync_file->user_name));
>> return sync_file;
>> -
>> -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)
>> diff --git a/include/linux/dma-fence-unwrap.h b/include/linux/dma-fence-unwrap.h
>> index e7c219da4ed7..7c0fab318301 100644
>> --- a/include/linux/dma-fence-unwrap.h
>> +++ b/include/linux/dma-fence-unwrap.h
>> @@ -48,4 +48,28 @@ struct dma_fence *dma_fence_unwrap_next(struct dma_fence_unwrap *cursor);
>> for (fence = dma_fence_unwrap_first(head, cursor); fence; \
>> fence = dma_fence_unwrap_next(cursor))
>>
>> +struct dma_fence *__dma_fence_merge(unsigned int num_fences,
>> + struct dma_fence **fences,
>> + struct dma_fence_unwrap *cursors);
>> +
>> +/**
>> + * dma_fence_merge - unwrap and merge fences
>> + *
>> + * All fences given as parameters are unwrapped and merged back together as flat
>> + * dma_fence_array. Useful if multiple containers need to be merged together.
>> + *
>> + * Implemented as a macro to allocate the necessary arrays on the stack and
>> + * account the stack frame size to the caller.
>> + *
>> + * Returns NULL on memory allocation failure, a dma_fence object representing
>> + * all the given fences otherwise.
>> + */
>> +#define dma_fence_merge(...) \
>> + ({ \
>> + struct dma_fence *__f[] = { __VA_ARGS__ }; \
>> + struct dma_fence_unwrap __c[ARRAY_SIZE(__f)]; \
>> + \
>> + __dma_fence_merge(ARRAY_SIZE(__f), __f, __c); \
>> + })
>> +
>> #endif
>> --
>> 2.25.1
>>
next prev parent reply other threads:[~2022-05-04 8:53 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-04-26 12:46 [PATCH 1/3] dma-buf/sync_file: cleanup fence merging a bit Christian König
2022-04-26 12:46 ` [PATCH 2/3] dma-buf: cleanup dma_fence_unwrap implementation and selftest Christian König
2022-05-04 8:37 ` Daniel Vetter
2022-04-26 12:46 ` [PATCH 3/3] dma-buf: generalize fence merging Christian König
2022-05-04 8:43 ` Daniel Vetter
2022-05-04 8:52 ` Christian König [this message]
2022-05-04 9:24 ` Daniel Vetter
2022-05-04 8:34 ` [PATCH 1/3] dma-buf/sync_file: cleanup fence merging a bit Daniel Vetter
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=09d1cd03-1da0-bb7a-5770-a75de67dffc8@amd.com \
--to=christian.koenig@amd.com \
--cc=ckoenig.leichtzumerken@gmail.com \
--cc=daniel.vetter@ffwll.ch \
--cc=daniel@ffwll.ch \
--cc=dri-devel@lists.freedesktop.org \
--cc=gustavo@padovan.org \
--cc=linaro-mm-sig@lists.linaro.org \
--cc=linux-media@vger.kernel.org \
--cc=sumit.semwal@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox