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 on DRM drivers. So even if there are many fences in the sync_file that needs to waited for a commit to happen, they all get added to the fence_collection and passed for DRM use as 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, so fence_is_later() and fence_later() are not meant to be called with fence_collections fences. v2: Comments by Daniel Vetter: - merge fence_collection_init() and fence_collection_add() - only add callbacks at ->enable_signalling() - remove fence_collection_put() - check for type on to_fence_collection() - adjust fence_is_later() and fence_later() to WARN_ON() if they are used with collection fences. v3: - Initialize fence_cb.node at fence init. Comments by Chris Wilson: - return "unbound" on fence_collection_get_timeline_name() - don't stop adding callbacks if one fails - remove redundant !! on fence_collection_enable_signaling() - remove redundant () on fence_collection_signaled - use fence_default_wait() instead v4 (chk): Rework, simplification and cleanup: - Drop FENCE_NO_CONTEXT handling, always allocate a context. - Rename to fence_array. - Return fixed driver name. - Register only one callback at a time. - Document that create function takes ownership of array. Signed-off-by: Gustavo Padovan <gustavo.padovan@xxxxxxxxxxxxxxx> Signed-off-by: Christian König <christian.koenig@xxxxxxx> --- drivers/dma-buf/Makefile | 2 +- drivers/dma-buf/fence-array.c | 132 ++++++++++++++++++++++++++++++++++++++++++ include/linux/fence-array.h | 62 ++++++++++++++++++++ 3 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 drivers/dma-buf/fence-array.c create mode 100644 include/linux/fence-array.h diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile index 57a675f..85f6928 100644 --- a/drivers/dma-buf/Makefile +++ b/drivers/dma-buf/Makefile @@ -1 +1 @@ -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-array.o diff --git a/drivers/dma-buf/fence-array.c b/drivers/dma-buf/fence-array.c new file mode 100644 index 0000000..a700c6e --- /dev/null +++ b/drivers/dma-buf/fence-array.c @@ -0,0 +1,132 @@ +/* + * fence-array: aggregate fences to be waited together + * + * Copyright (C) 2016 Collabora Ltd + * Copyright (C) 2016 Advanced Micro Devices, Inc. + * Authors: + * Gustavo Padovan <gustavo@xxxxxxxxxxx> + * Christian König <christian.koenig@xxxxxxx> + * + * 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-array.h> + +static void fence_array_cb_func(struct fence *f, struct fence_cb *cb); + +static const char *fence_array_get_driver_name(struct fence *fence) +{ + return "fence_array"; +} + +static const char *fence_array_get_timeline_name(struct fence *fence) +{ + return "unbound"; +} + +static bool fence_array_add_next_callback(struct fence_array *array) +{ + while (array->num_signaled < array->num_fences) { + struct fence *next = array->fences[array->num_signaled]; + + if (!fence_add_callback(next, &array->cb, fence_array_cb_func)) + return true; + + ++array->num_signaled; + } + + return false; +} + +static void fence_array_cb_func(struct fence *f, struct fence_cb *cb) +{ + struct fence_array *array = container_of(cb, struct fence_array, cb); + + ++array->num_signaled; + if (!fence_array_add_next_callback(array)) + fence_signal(&array->base); +} + +static bool fence_array_enable_signaling(struct fence *fence) +{ + struct fence_array *array = to_fence_array(fence); + + return fence_array_add_next_callback(array); +} + +static bool fence_array_signaled(struct fence *fence) +{ + struct fence_array *array = to_fence_array(fence); + + return ACCESS_ONCE(array->num_signaled) == array->num_fences; +} + +static void fence_array_release(struct fence *fence) +{ + struct fence_array *array = to_fence_array(fence); + unsigned i; + + i = ACCESS_ONCE(array->num_signaled); + if (i < array->num_fences) { + struct fence *last = array->fences[i]; + + fence_remove_callback(last, &array->cb); + } + + for (i = 0; i < array->num_fences; ++i) + fence_put(array->fences[i]); + + kfree(array->fences); + fence_free(fence); +} + +const struct fence_ops fence_array_ops = { + .get_driver_name = fence_array_get_driver_name, + .get_timeline_name = fence_array_get_timeline_name, + .enable_signaling = fence_array_enable_signaling, + .signaled = fence_array_signaled, + .wait = fence_default_wait, + .release = fence_array_release, +}; + +/** + * fence_array_create - Create a custom fence array + * @num_fences: [in] number of fences to add in the array + * @fences: [in] array containing the fences + * + * Allocate a fence_array object and initialize the base fence with fence_init(). + * In case of error it returns NULL. + * + * The caller should allocte the fences array with num_fences size + * and fill it with the fences it wants to add to the object. Ownership of this + * array is take and fence_put() is used on each fence on release. + */ +struct fence_array *fence_array_create(int num_fences, struct fence **fences) +{ + struct fence_array *array; + int i; + + array = kzalloc(sizeof(*array), GFP_KERNEL); + if (!array) + return NULL; + + spin_lock_init(&array->lock); + fence_init(&array->base, &fence_array_ops, &array->lock, + fence_context_alloc(1), 0); + + array->num_signaled = 0; + array->num_fences = num_fences; + array->fences = fences; + + return array; +} +EXPORT_SYMBOL(fence_array_create); diff --git a/include/linux/fence-array.h b/include/linux/fence-array.h new file mode 100644 index 0000000..f1daeb3 --- /dev/null +++ b/include/linux/fence-array.h @@ -0,0 +1,62 @@ +/* + * fence-array: aggregates fence to be waited together + * + * Copyright (C) 2016 Collabora Ltd + * Copyright (C) 2016 Advanced Micro Devices, Inc. + * Authors: + * Gustavo Padovan <gustavo@xxxxxxxxxxx> + * Christian König <christian.koenig@xxxxxxx> + * + * 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_ARRAY_H +#define __LINUX_FENCE_ARRAY_H + +#include <linux/fence.h> + +/** + * struct fence_array - fence to represent an array of fences + * @base: fence base class + * @lock: spinlock for fence handling + * @cb: fence callback structure for signaling + * @num_signaled: fences in the array already signaled + * @num_fences: number of fences in the array + * @fences: array of the fences + */ +struct fence_array { + struct fence base; + + spinlock_t lock; + struct fence_cb cb; + unsigned num_signaled; + unsigned num_fences; + struct fence **fences; +}; + +extern const struct fence_ops fence_array_ops; + +/** + * to_fence_array - cast a fence to a fence_array + * @fence: fence to cast to a fence_array + * + * Returns NULL if the fence is not a fence_array, + * or the fence_array otherwise. + */ +static inline struct fence_array *to_fence_array(struct fence *fence) +{ + if (fence->ops != &fence_array_ops) + return NULL; + return container_of(fence, struct fence_array, base); +} + +struct fence_array *fence_array_create(int num_fences, struct fence **fences); + +#endif /* __LINUX_FENCE_ARRAY_H */ -- 2.5.0 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel