[3/9] dma-buf: add dma_fence_array_alloc/free
diff mbox series

Message ID 20190826145731.1725-4-christian.koenig@amd.com
State New
Headers show
Series
  • [1/9] dma-buf: fix dma_fence_array_signaled
Related show

Commit Message

Christian König Aug. 26, 2019, 2:57 p.m. UTC
This seperates allocation and initialization of the dma_fence_array object
and allows allocating the fence array together with the dma_fence_array.

Signed-off-by: Christian König <christian.koenig@amd.com>
---
 drivers/dma-buf/dma-fence-array.c | 101 ++++++++++++++++++++----------
 include/linux/dma-fence-array.h   |  50 +++++++++++++--
 2 files changed, 115 insertions(+), 36 deletions(-)

Patch
diff mbox series

diff --git a/drivers/dma-buf/dma-fence-array.c b/drivers/dma-buf/dma-fence-array.c
index 52068ee5eb35..4664607f0abc 100644
--- a/drivers/dma-buf/dma-fence-array.c
+++ b/drivers/dma-buf/dma-fence-array.c
@@ -119,14 +119,7 @@  static bool dma_fence_array_signaled(struct dma_fence *fence)
 
 static void dma_fence_array_release(struct dma_fence *fence)
 {
-	struct dma_fence_array *array = to_dma_fence_array(fence);
-	unsigned i;
-
-	for (i = 0; i < array->num_fences; ++i)
-		dma_fence_put(array->fences[i]);
-
-	kfree(array->fences);
-	dma_fence_free(fence);
+	dma_fence_array_free(container_of(fence, struct dma_fence_array, base));
 }
 
 const struct dma_fence_ops dma_fence_array_ops = {
@@ -139,52 +132,96 @@  const struct dma_fence_ops dma_fence_array_ops = {
 EXPORT_SYMBOL(dma_fence_array_ops);
 
 /**
- * dma_fence_array_create - Create a custom fence array
+ * dma_fence_array_alloc - Allocate a custom fence array
  * @num_fences:		[in]	number of fences to add in the array
- * @fences:		[in]	array containing the fences
- * @context:		[in]	fence context to use
- * @seqno:		[in]	sequence number to use
- * @signal_on_any:	[in]	signal on any fence in the array
+ * @fences:		[in]	optional array containing the fences
  *
- * Allocate a dma_fence_array object and initialize the base fence with
- * dma_fence_init().
- * In case of error it returns NULL.
+ * Allocate a dma_fence_array object, in case of error it returns NULL.
  *
- * The caller should allocate 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 taken and dma_fence_put() is used on each fence on release.
- *
- * If @signal_on_any is true the fence array signals if any fence in the array
- * signals, otherwise it signals when all fences in the array signal.
+ * The fences array is optional and if NULL allocated together with the
+ * dma_fence_array object.
  */
-struct dma_fence_array *dma_fence_array_create(int num_fences,
-					       struct dma_fence **fences,
-					       u64 context, unsigned seqno,
-					       bool signal_on_any)
+struct dma_fence_array *dma_fence_array_alloc(int num_fences,
+					      struct dma_fence **fences)
 {
 	struct dma_fence_array *array;
 	size_t size = sizeof(*array);
 
 	/* Allocate the callback structures behind the array. */
 	size += num_fences * sizeof(struct dma_fence_array_cb);
+
+	/* Allocate the fences structures behind the callbacks */
+	if (!fences)
+		size += num_fences * sizeof(struct dma_fence *);
+
 	array = kzalloc(size, GFP_KERNEL);
 	if (!array)
 		return NULL;
 
+	if (!fences) {
+		struct dma_fence_array_cb *cb = (void *)(&array[1]);
+
+		num_fences = dma_fence_array_max_fences(array);
+		fences = (void *)(&cb[num_fences]);
+	}
+	array->fences = fences;
+	return array;
+}
+EXPORT_SYMBOL(dma_fence_array_alloc);
+
+/**
+ * dma_fence_array_init - init a custom fence array
+ * @array:		[in]	the pre-allocated array to init
+ * @context:		[in]	fence context to use
+ * @seqno:		[in]	sequence number to use
+ * @signal_on_any:	[in]	signal on any fence in the array
+ *
+ * Initialize the base fence with dma_fence_init().
+ *
+ * The caller should allocate 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 taken and dma_fence_put() is used on each fence on release.
+ *
+ * If @signal_on_any is true the fence array signals if any fence in the array
+ * signals, otherwise it signals when all fences in the array signal.
+ */
+void dma_fence_array_init(struct dma_fence_array *array, u64 context,
+			  unsigned int seqno, bool signal_on_any)
+{
 	spin_lock_init(&array->lock);
 	dma_fence_init(&array->base, &dma_fence_array_ops, &array->lock,
 		       context, seqno);
 	init_irq_work(&array->work, irq_dma_fence_array_work);
 
-	array->num_fences = num_fences;
-	atomic_set(&array->num_pending, signal_on_any ? 1 : num_fences);
-	array->fences = fences;
-
+	atomic_set(&array->num_pending, signal_on_any ? 1 : array->num_fences);
 	array->base.error = PENDING_ERROR;
+}
+EXPORT_SYMBOL(dma_fence_array_init);
 
-	return array;
+/**
+ * dma_fence_array_free - free a dma_fence_array object
+ * @array: the object to free
+ *
+ * The a dma_fence_array and drop all references to the fences it contains.
+ */
+void dma_fence_array_free(struct dma_fence_array *array)
+{
+	unsigned i;
+
+	if (!array)
+		return;
+
+	for (i = 0; i < array->num_fences; ++i)
+		dma_fence_put(array->fences[i]);
+
+	/* Check if fences are part of the array */
+	if ((u8 *)array->fences < (u8 *)array ||
+	    (u8 *)array->fences > ((u8 *)array) + ksize(array))
+		kfree(array->fences);
+
+	dma_fence_free(&array->base);
 }
-EXPORT_SYMBOL(dma_fence_array_create);
+EXPORT_SYMBOL(dma_fence_array_free);
 
 /**
  * dma_fence_match_context - Check if all fences are from the given context
diff --git a/include/linux/dma-fence-array.h b/include/linux/dma-fence-array.h
index f99cd7eb24e0..be85c06b524d 100644
--- a/include/linux/dma-fence-array.h
+++ b/include/linux/dma-fence-array.h
@@ -14,6 +14,7 @@ 
 
 #include <linux/dma-fence.h>
 #include <linux/irq_work.h>
+#include <linux/slab.h>
 
 /**
  * struct dma_fence_array_cb - callback helper for fence array
@@ -74,10 +75,51 @@  to_dma_fence_array(struct dma_fence *fence)
 	return container_of(fence, struct dma_fence_array, base);
 }
 
-struct dma_fence_array *dma_fence_array_create(int num_fences,
-					       struct dma_fence **fences,
-					       u64 context, unsigned seqno,
-					       bool signal_on_any);
+/**
+ * dma_fence_array_max_fences - calculate maximum number of fences
+ * @array:	[in]	the dma_fence_array to use
+ *
+ * Returns the maximum number of fences a dma_fence_array can store.
+ */
+static inline unsigned int
+dma_fence_array_max_fences(struct dma_fence_array *array)
+{
+	return (ksize(array) - sizeof(*array)) /
+		(sizeof(struct dma_fence_array_cb) +
+		 sizeof(struct dma_fence *));
+}
+
+struct dma_fence_array *dma_fence_array_alloc(int num_fences,
+					      struct dma_fence **fences);
+void dma_fence_array_init(struct dma_fence_array *array, u64 context,
+			  unsigned int seqno, bool signal_on_any);
+void dma_fence_array_free(struct dma_fence_array *array);
+
+/**
+ * dma_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
+ * @context:		[in]	fence context to use
+ * @seqno:		[in]	sequence number to use
+ * @signal_on_any:	[in]	signal on any fence in the array
+ *
+ * Wrapper around dma_fence_array_alloc and dma_fence_array_init. Returns NULL
+ * on allocation failure.
+ */
+static inline struct dma_fence_array *
+dma_fence_array_create(int num_fences, struct dma_fence **fences, u64 context,
+		       unsigned seqno, bool signal_on_any)
+{
+	struct dma_fence_array *array;
+
+	array = dma_fence_array_alloc(num_fences, fences);
+	if (!array)
+		return NULL;
+
+	array->num_fences = num_fences;
+	dma_fence_array_init(array, context, seqno, signal_on_any);
+	return array;
+}
 
 bool dma_fence_match_context(struct dma_fence *fence, u64 context);