From: Gustavo Padovan <gustavo.padovan@xxxxxxxxxxxxxxx> struct fence_collection inherits from struct fence and carries a collection of fences that needs to be waited together. It is useful to translate a sync_file to a fence to remove the complexity of dealing with sync_files from DRM drivers. So even if there are many fences in the sync_file that needs to waited for a commit to happen drivers would only worry about a standard struct fence.That means that no changes needed to any driver besides supporting fences. fence_collection's fence doesn't belong to any timeline context. Signed-off-by: Gustavo Padovan <gustavo.padovan@xxxxxxxxxxxxxxx> --- drivers/dma-buf/Makefile | 2 +- drivers/dma-buf/fence-collection.c | 138 +++++++++++++++++++++++++++++++++++++ drivers/dma-buf/fence.c | 2 +- include/linux/fence-collection.h | 56 +++++++++++++++ include/linux/fence.h | 2 + 5 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 drivers/dma-buf/fence-collection.c create mode 100644 include/linux/fence-collection.h diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile index 43325a1..30b8464 100644 --- a/drivers/dma-buf/Makefile +++ b/drivers/dma-buf/Makefile @@ -1,3 +1,3 @@ -obj-y := dma-buf.o fence.o reservation.o seqno-fence.o +obj-y := dma-buf.o fence.o reservation.o seqno-fence.o fence-collection.o obj-$(CONFIG_SYNC_FILE) += sync_file.o sync_timeline.o sync_debug.o obj-$(CONFIG_SW_SYNC) += sw_sync.o diff --git a/drivers/dma-buf/fence-collection.c b/drivers/dma-buf/fence-collection.c new file mode 100644 index 0000000..8a4ecb0 --- /dev/null +++ b/drivers/dma-buf/fence-collection.c @@ -0,0 +1,138 @@ +/* + * fence-collection: aggregate fences to be waited together + * + * Copyright (C) 2016 Collabora Ltd + * Authors: + * Gustavo Padovan <gustavo@xxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include <linux/export.h> +#include <linux/slab.h> +#include <linux/fence-collection.h> + +static const char *fence_collection_get_driver_name(struct fence *fence) +{ + struct fence_collection *collection = to_fence_collection(fence); + struct fence *f = collection->fences[0].fence; + + return f->ops->get_driver_name(fence); +} + +static const char *fence_collection_get_timeline_name(struct fence *fence) +{ + return "no context"; +} + +static bool fence_collection_enable_signaling(struct fence *fence) +{ + struct fence_collection *collection = to_fence_collection(fence); + + return atomic_read(&collection->num_pending_fences); +} + +static bool fence_collection_signaled(struct fence *fence) +{ + struct fence_collection *collection = to_fence_collection(fence); + + return (atomic_read(&collection->num_pending_fences) == 0); +} + +static void fence_collection_release(struct fence *fence) +{ + struct fence_collection *collection = to_fence_collection(fence); + int i; + + for (i = 0 ; i < collection->num_fences ; i++) { + fence_remove_callback(collection->fences[i].fence, + &collection->fences[i].cb); + fence_put(collection->fences[i].fence); + } + + fence_free(fence); +} + +static signed long fence_collection_wait(struct fence *fence, bool intr, + signed long timeout) +{ + struct fence_collection *collection = to_fence_collection(fence); + int i; + + for (i = 0 ; i < collection->num_fences ; i++) { + timeout = fence_wait(collection->fences[i].fence, intr); + if (timeout < 0) + return timeout; + } + + return timeout; +} + +static const struct fence_ops fence_collection_ops = { + .get_driver_name = fence_collection_get_driver_name, + .get_timeline_name = fence_collection_get_timeline_name, + .enable_signaling = fence_collection_enable_signaling, + .signaled = fence_collection_signaled, + .wait = fence_collection_wait, + .release = fence_collection_release, +}; + +static void collection_check_cb_func(struct fence *fence, struct fence_cb *cb) +{ + struct fence_collection_cb *f_cb; + struct fence_collection *collection; + + f_cb = container_of(cb, struct fence_collection_cb, cb); + collection = f_cb->collection; + + if (atomic_dec_and_test(&collection->num_pending_fences)) + fence_signal(&collection->base); +} + +void fence_collection_add(struct fence_collection *collection, + struct fence *fence) +{ + int n = collection->num_fences; + + collection->fences[n].collection = collection; + collection->fences[n].fence = fence; + + if (fence_add_callback(fence, &collection->fences[n].cb, + collection_check_cb_func)) + return; + + fence_get(fence); + + collection->num_fences++; + atomic_inc(&collection->num_pending_fences); +} + +struct fence_collection *fence_collection_init(int num_fences) +{ + struct fence_collection *collection; + + collection = kzalloc(offsetof(struct fence_collection, + fences[num_fences]), GFP_KERNEL); + if (!collection) + return NULL; + + spin_lock_init(&collection->lock); + fence_init(&collection->base, &fence_collection_ops, &collection->lock, + FENCE_NO_CONTEXT, 0); + + return collection; +} +EXPORT_SYMBOL(fence_collection_init); + +void fence_collection_put(struct fence_collection *collection) +{ + fence_put(&collection->base); +} +EXPORT_SYMBOL(fence_collection_put); diff --git a/drivers/dma-buf/fence.c b/drivers/dma-buf/fence.c index 7b05dbe..486e95c 100644 --- a/drivers/dma-buf/fence.c +++ b/drivers/dma-buf/fence.c @@ -35,7 +35,7 @@ EXPORT_TRACEPOINT_SYMBOL(fence_emit); * context or not. One device can have multiple separate contexts, * and they're used if some engine can run independently of another. */ -static atomic_t fence_context_counter = ATOMIC_INIT(0); +static atomic_t fence_context_counter = ATOMIC_INIT(1); /** * fence_context_alloc - allocate an array of fence contexts diff --git a/include/linux/fence-collection.h b/include/linux/fence-collection.h new file mode 100644 index 0000000..a798925 --- /dev/null +++ b/include/linux/fence-collection.h @@ -0,0 +1,56 @@ +/* + * fence-collection: aggregates fence to be waited together + * + * Copyright (C) 2016 Collabora Ltd + * Authors: + * Gustavo Padovan <gustavo@xxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef __LINUX_FENCE_COLLECTION_H +#define __LINUX_FENCE_COLLECTION_H + +#include <linux/fence.h> + +struct fence_collection_cb { + struct fence_cb cb; + struct fence *fence; + struct fence_collection *collection; +}; + +struct fence_collection { + struct fence base; + + spinlock_t lock; + struct fence_cb fence_cb; + atomic_t num_pending_fences; + int num_fences; + struct fence_collection_cb fences[]; +}; + +/** + * to_fence_collection - cast a fence to a fence_collection + * @fence: fence to cast to a fence_collection + * + * Returns NULL if the fence is not a fence_collection, + * or the fence_collection otherwise. + */ +static inline struct fence_collection * to_fence_collection(struct fence *fence) +{ + return container_of(fence, struct fence_collection, base); +} + +struct fence_collection *fence_collection_init(int num_fences); +void fence_collection_add(struct fence_collection *collection, + struct fence *fence); +void fence_collection_put(struct fence_collection *collection); + +#endif /* __LINUX_FENCE_COLLECTION_H */ diff --git a/include/linux/fence.h b/include/linux/fence.h index 2b17698..02170dd 100644 --- a/include/linux/fence.h +++ b/include/linux/fence.h @@ -30,6 +30,8 @@ #include <linux/printk.h> #include <linux/rcupdate.h> +#define FENCE_NO_CONTEXT 0 + struct fence; struct fence_ops; struct fence_cb; -- 2.5.5 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel