[RFC 11/29] dma-buf/fence: move sync_timeline to fence_timeline

From: Gustavo Padovan
Date: Fri Jan 15 2016 - 10:01:46 EST


From: Gustavo Padovan <gustavo.padovan@xxxxxxxxxxxxxxx>

Add the sync timeline from sync framework to fence synchronization system.
This is an attempt to remove some duplication between sync.c and fence.c

The sync_timeline was no more than a wrapper on top of the fence
framework to be used by sw_sync. It simplifies some accesses, for example,
when you have a struct fence you don't need get the sync_pt related to it
to know the parent timeline, it is just a matter of calling
fence_parent() now.

This is just the initial step, the idea is to connect sw_sync direct
with fences removing some abstractions in between.

The sync API changes here are:

* struct sync_timeline is now struct fence_timeline
* sync_timeline_ops is now fence_timeline_ops and they now carry struct
fence as parameter instead of struct sync_pt
* sync_timeline_create() -> fence_timeline_create()
* sync_timeline_get() -> fence_timeline_get()
* sync_timeline_put() -> fence_timeline_put()
* sync_timeline_destroy() -> fence_timeline_destroy()
* sync_timeline_signal() -> fence_timeline_signal()

Signed-off-by: Gustavo Padovan <gustavo.padovan@xxxxxxxxxxxxxxx>
---
drivers/dma-buf/fence.c | 125 +++++++++++++++++++++++++++++
drivers/staging/android/sw_sync.c | 27 ++++---
drivers/staging/android/sw_sync.h | 2 +-
drivers/staging/android/sync.c | 150 +++++++----------------------------
drivers/staging/android/sync.h | 130 +-----------------------------
drivers/staging/android/sync_debug.c | 26 +++---
drivers/staging/android/trace/sync.h | 24 ------
include/linux/fence.h | 75 ++++++++++++++++++
include/trace/events/fence.h | 24 ++++++
9 files changed, 285 insertions(+), 298 deletions(-)

diff --git a/drivers/dma-buf/fence.c b/drivers/dma-buf/fence.c
index 7b05dbe..5dcb94c 100644
--- a/drivers/dma-buf/fence.c
+++ b/drivers/dma-buf/fence.c
@@ -52,6 +52,131 @@ unsigned fence_context_alloc(unsigned num)
EXPORT_SYMBOL(fence_context_alloc);

/**
+ * fence_timeline_create - create a new fence_timeline
+ * @num: [in] amount of contexts to allocate
+ * @ops: [in] timeline ops of the caller
+ * @size: [in] size to allocate struct fence_timeline
+ * @name: [in] name of the timeline
+ *
+ * This function will return the new fence_timeline or NULL in case of error.
+ * It allocs and initializes a new fence_timeline with a proper fence context
+ * number assigned to it.
+ */
+struct fence_timeline *fence_timeline_create(unsigned num,
+ struct fence_timeline_ops *ops,
+ int size, const char *name)
+{
+ struct fence_timeline *timeline;
+
+ if (size < sizeof(*timeline))
+ return NULL;
+
+ timeline = kzalloc(size, GFP_KERNEL);
+ if (!timeline)
+ return NULL;
+
+ kref_init(&timeline->kref);
+ timeline->ops = ops;
+ timeline->context = fence_context_alloc(1);
+ strlcpy(timeline->name, name, sizeof(timeline->name));
+
+ INIT_LIST_HEAD(&timeline->child_list_head);
+ INIT_LIST_HEAD(&timeline->active_list_head);
+ spin_lock_init(&timeline->lock);
+
+ return timeline;
+}
+EXPORT_SYMBOL(fence_timeline_create);
+
+/**
+ * fence_timeline_free - free resources of fence_timeline
+ * @kref [in] the kref of the fence_timeline to be freed
+ *
+ * This function frees a fence_timeline which is matter of a simple
+ * call to kfree()
+ */
+static void fence_timeline_free(struct kref *kref)
+{
+ struct fence_timeline *timeline =
+ container_of(kref, struct fence_timeline, kref);
+
+ kfree(timeline);
+}
+
+/**
+ * fence_timeline_get - get a reference to the timeline
+ * @timeline [in] the fence_timeline to get a reference
+ *
+ * This function increase the refcnt for the given timeline.
+ */
+void fence_timeline_get(struct fence_timeline *timeline)
+{
+ kref_get(&timeline->kref);
+}
+EXPORT_SYMBOL(fence_timeline_get);
+
+/**
+ * fence_timeline_put - put a reference to the timeline
+ * @timeline [in] the fence_timeline to put a reference
+ *
+ * This function decreases the refcnt for the given timeline
+ * and frees it if gets to zero.
+ */
+void fence_timeline_put(struct fence_timeline *timeline)
+{
+ kref_put(&timeline->kref, fence_timeline_free);
+}
+EXPORT_SYMBOL(fence_timeline_put);
+
+/**
+ * fence_timeline_destroy - destroy a fence_timeline
+ * @timeline [in] the fence_timeline to destroy
+ *
+ * This function destroys a timeline. It signals any active fence first.
+ */
+void fence_timeline_destroy(struct fence_timeline *timeline)
+{
+ timeline->destroyed = true;
+ /*
+ * Ensure timeline is marked as destroyed before
+ * changing timeline's fences status.
+ */
+ smp_wmb();
+
+ /*
+ * signal any children that their parent is going away.
+ */
+ fence_timeline_signal(timeline);
+ fence_timeline_put(timeline);
+}
+EXPORT_SYMBOL(fence_timeline_destroy);
+
+/**
+ * fence_timeline_signal - signal fences on a fence_timeline
+ * @timeline [in] the fence_timeline to signal fences
+ *
+ * This function signal fences on a given timeline and remove
+ * those from the active_list.
+ */
+void fence_timeline_signal(struct fence_timeline *timeline)
+{
+ unsigned long flags;
+ LIST_HEAD(signaled_pts);
+ struct fence *fence, *next;
+
+ spin_lock_irqsave(&timeline->lock, flags);
+
+ list_for_each_entry_safe(fence, next, &timeline->active_list_head,
+ active_list) {
+ if (fence_is_signaled_locked(fence))
+ list_del_init(&fence->active_list);
+ }
+
+ spin_unlock_irqrestore(&timeline->lock, flags);
+}
+EXPORT_SYMBOL(fence_timeline_signal);
+
+/**
* fence_signal_locked - signal completion of a fence
* @fence: the fence to signal
*
diff --git a/drivers/staging/android/sw_sync.c b/drivers/staging/android/sw_sync.c
index f491dbc..98f9a29 100644
--- a/drivers/staging/android/sw_sync.c
+++ b/drivers/staging/android/sw_sync.c
@@ -38,18 +38,19 @@ struct sync_pt *sw_sync_pt_create(struct sw_sync_timeline *obj, u32 value)
}
EXPORT_SYMBOL(sw_sync_pt_create);

-static int sw_sync_pt_has_signaled(struct sync_pt *sync_pt)
+static int sw_sync_fence_has_signaled(struct fence *fence)
{
- struct sw_sync_pt *pt = (struct sw_sync_pt *)sync_pt;
+ struct sw_sync_pt *pt = (struct sw_sync_pt *)fence;
struct sw_sync_timeline *obj =
- (struct sw_sync_timeline *)sync_pt_parent(sync_pt);
+ (struct sw_sync_timeline *)fence_parent(fence);

return (pt->value > obj->value) ? 0 : 1;
}

-static int sw_sync_fill_driver_data(struct sync_pt *sync_pt,
+static int sw_sync_fill_driver_data(struct fence *fence,
void *data, int size)
{
+ struct sync_pt *sync_pt = (struct sync_pt *)fence;
struct sw_sync_pt *pt = (struct sw_sync_pt *)sync_pt;

if (size < sizeof(pt->value))
@@ -60,34 +61,34 @@ static int sw_sync_fill_driver_data(struct sync_pt *sync_pt,
return sizeof(pt->value);
}

-static void sw_sync_timeline_value_str(struct sync_timeline *sync_timeline,
+static void sw_sync_timeline_value_str(struct fence_timeline *fence_timeline,
char *str, int size)
{
struct sw_sync_timeline *timeline =
- (struct sw_sync_timeline *)sync_timeline;
+ (struct sw_sync_timeline *)fence_timeline;
snprintf(str, size, "%d", timeline->value);
}

-static void sw_sync_pt_value_str(struct sync_pt *sync_pt,
+static void sw_sync_fence_value_str(struct fence *fence,
char *str, int size)
{
- struct sw_sync_pt *pt = (struct sw_sync_pt *)sync_pt;
+ struct sw_sync_pt *pt = (struct sw_sync_pt *)fence;

snprintf(str, size, "%d", pt->value);
}

-static struct sync_timeline_ops sw_sync_timeline_ops = {
+static struct fence_timeline_ops sw_sync_timeline_ops = {
.driver_name = "sw_sync",
- .has_signaled = sw_sync_pt_has_signaled,
+ .has_signaled = sw_sync_fence_has_signaled,
.fill_driver_data = sw_sync_fill_driver_data,
.timeline_value_str = sw_sync_timeline_value_str,
- .pt_value_str = sw_sync_pt_value_str,
+ .fence_value_str = sw_sync_fence_value_str,
};

struct sw_sync_timeline *sw_sync_timeline_create(const char *name)
{
struct sw_sync_timeline *obj = (struct sw_sync_timeline *)
- sync_timeline_create(&sw_sync_timeline_ops,
+ fence_timeline_create(1, &sw_sync_timeline_ops,
sizeof(struct sw_sync_timeline),
name);

@@ -99,6 +100,6 @@ void sw_sync_timeline_inc(struct sw_sync_timeline *obj, u32 inc)
{
obj->value += inc;

- sync_timeline_signal(&obj->obj);
+ fence_timeline_signal(&obj->obj);
}
EXPORT_SYMBOL(sw_sync_timeline_inc);
diff --git a/drivers/staging/android/sw_sync.h b/drivers/staging/android/sw_sync.h
index c87ae9e..cb62298 100644
--- a/drivers/staging/android/sw_sync.h
+++ b/drivers/staging/android/sw_sync.h
@@ -23,7 +23,7 @@
#include "uapi/sw_sync.h"

struct sw_sync_timeline {
- struct sync_timeline obj;
+ struct fence_timeline obj;

u32 value;
};
diff --git a/drivers/staging/android/sync.c b/drivers/staging/android/sync.c
index decff9e..b07bc24 100644
--- a/drivers/staging/android/sync.c
+++ b/drivers/staging/android/sync.c
@@ -34,110 +34,26 @@
static const struct fence_ops sync_fence_ops;
static const struct file_operations sync_fence_fops;

-struct sync_timeline *sync_timeline_create(const struct sync_timeline_ops *ops,
- int size, const char *name)
-{
- struct sync_timeline *obj;
-
- if (size < sizeof(struct sync_timeline))
- return NULL;
-
- obj = kzalloc(size, GFP_KERNEL);
- if (!obj)
- return NULL;
-
- kref_init(&obj->kref);
- obj->ops = ops;
- obj->context = fence_context_alloc(1);
- strlcpy(obj->name, name, sizeof(obj->name));
-
- INIT_LIST_HEAD(&obj->child_list_head);
- INIT_LIST_HEAD(&obj->active_list_head);
- spin_lock_init(&obj->child_list_lock);
-
- sync_timeline_debug_add(obj);
-
- return obj;
-}
-EXPORT_SYMBOL(sync_timeline_create);
-
-static void sync_timeline_free(struct kref *kref)
-{
- struct sync_timeline *obj =
- container_of(kref, struct sync_timeline, kref);
-
- sync_timeline_debug_remove(obj);
-
- kfree(obj);
-}
-
-static void sync_timeline_get(struct sync_timeline *obj)
-{
- kref_get(&obj->kref);
-}
-
-static void sync_timeline_put(struct sync_timeline *obj)
-{
- kref_put(&obj->kref, sync_timeline_free);
-}
-
-void sync_timeline_destroy(struct sync_timeline *obj)
-{
- obj->destroyed = true;
- /*
- * Ensure timeline is marked as destroyed before
- * changing timeline's fences status.
- */
- smp_wmb();
-
- /*
- * signal any children that their parent is going away.
- */
- sync_timeline_signal(obj);
- sync_timeline_put(obj);
-}
-EXPORT_SYMBOL(sync_timeline_destroy);
-
-void sync_timeline_signal(struct sync_timeline *obj)
-{
- unsigned long flags;
- LIST_HEAD(signaled_pts);
- struct sync_pt *pt, *next;
-
- trace_sync_timeline(obj);
-
- spin_lock_irqsave(&obj->child_list_lock, flags);
-
- list_for_each_entry_safe(pt, next, &obj->active_list_head,
- active_list) {
- if (fence_is_signaled_locked(&pt->base))
- list_del_init(&pt->active_list);
- }
-
- spin_unlock_irqrestore(&obj->child_list_lock, flags);
-}
-EXPORT_SYMBOL(sync_timeline_signal);
-
-struct sync_pt *sync_pt_create(struct sync_timeline *obj, int size)
+struct fence *sync_pt_create(struct fence_timeline *obj, int size)
{
unsigned long flags;
- struct sync_pt *pt;
+ struct fence *fence;

if (size < sizeof(struct sync_pt))
return NULL;

- pt = kzalloc(size, GFP_KERNEL);
- if (!pt)
+ fence = kzalloc(size, GFP_KERNEL);
+ if (!fence)
return NULL;

- spin_lock_irqsave(&obj->child_list_lock, flags);
- sync_timeline_get(obj);
- fence_init(&pt->base, &sync_fence_ops, &obj->child_list_lock,
+ spin_lock_irqsave(&obj->lock, flags);
+ fence_timeline_get(obj);
+ fence_init(fence, &sync_fence_ops, &obj->lock,
obj->context, ++obj->value);
- list_add_tail(&pt->child_list, &obj->child_list_head);
- INIT_LIST_HEAD(&pt->active_list);
- spin_unlock_irqrestore(&obj->child_list_lock, flags);
- return pt;
+ list_add_tail(&fence->child_list, &obj->child_list_head);
+ INIT_LIST_HEAD(&fence->active_list);
+ spin_unlock_irqrestore(&obj->lock, flags);
+ return fence;
}
EXPORT_SYMBOL(sync_pt_create);

@@ -412,44 +328,40 @@ EXPORT_SYMBOL(sync_fence_wait);

static const char *sync_fence_get_driver_name(struct fence *fence)
{
- struct sync_pt *pt = container_of(fence, struct sync_pt, base);
- struct sync_timeline *parent = sync_pt_parent(pt);
+ struct fence_timeline *parent = fence_parent(fence);

return parent->ops->driver_name;
}

static const char *sync_fence_get_timeline_name(struct fence *fence)
{
- struct sync_pt *pt = container_of(fence, struct sync_pt, base);
- struct sync_timeline *parent = sync_pt_parent(pt);
+ struct fence_timeline *parent = fence_parent(fence);

return parent->name;
}

static void sync_fence_release(struct fence *fence)
{
- struct sync_pt *pt = container_of(fence, struct sync_pt, base);
- struct sync_timeline *parent = sync_pt_parent(pt);
+ struct fence_timeline *parent = fence_parent(fence);
unsigned long flags;

spin_lock_irqsave(fence->lock, flags);
- list_del(&pt->child_list);
- if (!list_empty(&pt->active_list))
- list_del(&pt->active_list);
+ list_del(&fence->child_list);
+ if (!list_empty(&fence->active_list))
+ list_del(&fence->active_list);

spin_unlock_irqrestore(fence->lock, flags);

- sync_timeline_put(parent);
- fence_free(&pt->base);
+ fence_timeline_put(parent);
+ fence_free(fence);
}

static bool sync_fence_signaled(struct fence *fence)
{
- struct sync_pt *pt = container_of(fence, struct sync_pt, base);
- struct sync_timeline *parent = sync_pt_parent(pt);
+ struct fence_timeline *parent = fence_parent(fence);
int ret;

- ret = parent->ops->has_signaled(pt);
+ ret = parent->ops->has_signaled(fence);
if (ret < 0)
fence->status = ret;
return ret;
@@ -457,46 +369,42 @@ static bool sync_fence_signaled(struct fence *fence)

static bool sync_fence_enable_signaling(struct fence *fence)
{
- struct sync_pt *pt = container_of(fence, struct sync_pt, base);
- struct sync_timeline *parent = sync_pt_parent(pt);
+ struct fence_timeline *parent = fence_parent(fence);

if (sync_fence_signaled(fence))
return false;

- list_add_tail(&pt->active_list, &parent->active_list_head);
+ list_add_tail(&fence->active_list, &parent->active_list_head);
return true;
}

static int sync_fence_fill_driver_data(struct fence *fence,
void *data, int size)
{
- struct sync_pt *pt = container_of(fence, struct sync_pt, base);
- struct sync_timeline *parent = sync_pt_parent(pt);
+ struct fence_timeline *parent = fence_parent(fence);

if (!parent->ops->fill_driver_data)
return 0;
- return parent->ops->fill_driver_data(pt, data, size);
+ return parent->ops->fill_driver_data(fence, data, size);
}

static void sync_fence_value_str(struct fence *fence,
char *str, int size)
{
- struct sync_pt *pt = container_of(fence, struct sync_pt, base);
- struct sync_timeline *parent = sync_pt_parent(pt);
+ struct fence_timeline *parent = fence_parent(fence);

- if (!parent->ops->pt_value_str) {
+ if (!parent->ops->fence_value_str) {
if (size)
*str = 0;
return;
}
- parent->ops->pt_value_str(pt, str, size);
+ parent->ops->fence_value_str(fence, str, size);
}

static void sync_fence_timeline_value_str(struct fence *fence,
char *str, int size)
{
- struct sync_pt *pt = container_of(fence, struct sync_pt, base);
- struct sync_timeline *parent = sync_pt_parent(pt);
+ struct fence_timeline *parent = fence_parent(fence);

if (!parent->ops->timeline_value_str) {
if (size)
diff --git a/drivers/staging/android/sync.h b/drivers/staging/android/sync.h
index 43f72a7..53658cc 100644
--- a/drivers/staging/android/sync.h
+++ b/drivers/staging/android/sync.h
@@ -23,91 +23,12 @@

#include "uapi/sync.h"

-struct sync_timeline;
-struct sync_pt;
struct sync_fence;

-/**
- * struct sync_timeline_ops - sync object implementation ops
- * @driver_name: name of the implementation
- * @has_signaled: returns:
- * 1 if pt has signaled
- * 0 if pt has not signaled
- * <0 on error
- * @fill_driver_data: write implementation specific driver data to data.
- * should return an error if there is not enough room
- * as specified by size. This information is returned
- * to userspace by SYNC_IOC_FENCE_INFO.
- * @timeline_value_str: fill str with the value of the sync_timeline's counter
- * @pt_value_str: fill str with the value of the sync_pt
- */
-struct sync_timeline_ops {
- const char *driver_name;
-
- /* required */
- int (*has_signaled)(struct sync_pt *pt);
-
- /* optional */
- int (*fill_driver_data)(struct sync_pt *syncpt, void *data, int size);
-
- /* optional */
- void (*timeline_value_str)(struct sync_timeline *timeline, char *str,
- int size);
-
- /* optional */
- void (*pt_value_str)(struct sync_pt *pt, char *str, int size);
-};
-
-/**
- * struct sync_timeline - sync object
- * @kref: reference count on fence.
- * @ops: ops that define the implementation of the sync_timeline
- * @name: name of the sync_timeline. Useful for debugging
- * @destroyed: set when sync_timeline is destroyed
- * @child_list_head: list of children sync_pts for this sync_timeline
- * @child_list_lock: lock protecting @child_list_head, destroyed, and
- * sync_pt.status
- * @active_list_head: list of active (unsignaled/errored) sync_pts
- * @sync_timeline_list: membership in global sync_timeline_list
- */
-struct sync_timeline {
- struct kref kref;
- const struct sync_timeline_ops *ops;
- char name[32];
-
- /* protected by child_list_lock */
- bool destroyed;
- int context, value;
-
- struct list_head child_list_head;
- spinlock_t child_list_lock;
-
- struct list_head active_list_head;
-
-#ifdef CONFIG_DEBUG_FS
- struct list_head sync_timeline_list;
-#endif
-};
-
-/**
- * struct sync_pt - sync point
- * @base: base fence class
- * @child_list: membership in sync_timeline.child_list_head
- * @active_list: membership in sync_timeline.active_list_head
- */
struct sync_pt {
struct fence base;
-
- struct list_head child_list;
- struct list_head active_list;
};

-static inline struct sync_timeline *sync_pt_parent(struct sync_pt *pt)
-{
- return container_of(pt->base.lock, struct sync_timeline,
- child_list_lock);
-}
-
struct sync_fence_cb {
struct fence_cb cb;
struct fence *fence;
@@ -162,53 +83,10 @@ static inline void sync_fence_waiter_init(struct sync_fence_waiter *waiter,
}

/*
- * API for sync_timeline implementers
+ * API for fence_timeline implementers
*/

-/**
- * sync_timeline_create() - creates a sync object
- * @ops: specifies the implementation ops for the object
- * @size: size to allocate for this obj
- * @name: sync_timeline name
- *
- * Creates a new sync_timeline which will use the implementation specified by
- * @ops. @size bytes will be allocated allowing for implementation specific
- * data to be kept after the generic sync_timeline struct. Returns the
- * sync_timeline object or NULL in case of error.
- */
-struct sync_timeline *sync_timeline_create(const struct sync_timeline_ops *ops,
- int size, const char *name);
-
-/**
- * sync_timeline_destroy() - destroys a sync object
- * @obj: sync_timeline to destroy
- *
- * A sync implementation should call this when the @obj is going away
- * (i.e. module unload.) @obj won't actually be freed until all its children
- * sync_pts are freed.
- */
-void sync_timeline_destroy(struct sync_timeline *obj);
-
-/**
- * sync_timeline_signal() - signal a status change on a sync_timeline
- * @obj: sync_timeline to signal
- *
- * A sync implementation should call this any time one of it's sync_pts
- * has signaled or has an error condition.
- */
-void sync_timeline_signal(struct sync_timeline *obj);
-
-/**
- * sync_pt_create() - creates a sync pt
- * @parent: sync_pt's parent sync_timeline
- * @size: size to allocate for this pt
- *
- * Creates a new sync_pt as a child of @parent. @size bytes will be
- * allocated allowing for implementation specific data to be kept after
- * the generic sync_timeline struct. Returns the sync_pt object or
- * NULL in case of error.
- */
-struct sync_pt *sync_pt_create(struct sync_timeline *parent, int size);
+struct fence *sync_pt_create(struct fence_timeline *parent, int size);

/**
* sync_pt_free() - frees a sync pt
@@ -325,8 +203,8 @@ int sync_fence_wait(struct sync_fence *fence, long timeout);

#ifdef CONFIG_DEBUG_FS

-void sync_timeline_debug_add(struct sync_timeline *obj);
-void sync_timeline_debug_remove(struct sync_timeline *obj);
+void sync_timeline_debug_add(struct fence_timeline *obj);
+void sync_timeline_debug_remove(struct fence_timeline *obj);
void sync_fence_debug_add(struct sync_fence *fence);
void sync_fence_debug_remove(struct sync_fence *fence);
void sync_dump(void);
diff --git a/drivers/staging/android/sync_debug.c b/drivers/staging/android/sync_debug.c
index 78e9147..f5fd8c3 100644
--- a/drivers/staging/android/sync_debug.c
+++ b/drivers/staging/android/sync_debug.c
@@ -38,21 +38,21 @@ static DEFINE_SPINLOCK(sync_timeline_list_lock);
static LIST_HEAD(sync_fence_list_head);
static DEFINE_SPINLOCK(sync_fence_list_lock);

-void sync_timeline_debug_add(struct sync_timeline *obj)
+void sync_timeline_debug_add(struct fence_timeline *obj)
{
unsigned long flags;

spin_lock_irqsave(&sync_timeline_list_lock, flags);
- list_add_tail(&obj->sync_timeline_list, &sync_timeline_list_head);
+ list_add_tail(&obj->fence_timeline_list, &sync_timeline_list_head);
spin_unlock_irqrestore(&sync_timeline_list_lock, flags);
}

-void sync_timeline_debug_remove(struct sync_timeline *obj)
+void sync_timeline_debug_remove(struct fence_timeline *obj)
{
unsigned long flags;

spin_lock_irqsave(&sync_timeline_list_lock, flags);
- list_del(&obj->sync_timeline_list);
+ list_del(&obj->fence_timeline_list);
spin_unlock_irqrestore(&sync_timeline_list_lock, flags);
}

@@ -127,7 +127,7 @@ static void sync_print_pt(struct seq_file *s, struct fence *pt, bool fence)
seq_puts(s, "\n");
}

-static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj)
+static void sync_print_obj(struct seq_file *s, struct fence_timeline *obj)
{
struct list_head *pos;
unsigned long flags;
@@ -143,13 +143,13 @@ static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj)

seq_puts(s, "\n");

- spin_lock_irqsave(&obj->child_list_lock, flags);
+ spin_lock_irqsave(&obj->lock, flags);
list_for_each(pos, &obj->child_list_head) {
- struct sync_pt *pt =
- container_of(pos, struct sync_pt, child_list);
+ struct sync_pt *pt = (struct sync_pt *)
+ container_of(pos, struct fence, child_list);
sync_print_pt(s, &pt->base, false);
}
- spin_unlock_irqrestore(&obj->child_list_lock, flags);
+ spin_unlock_irqrestore(&obj->lock, flags);
}

static void sync_print_sync_fence(struct seq_file *s,
@@ -189,9 +189,9 @@ static int sync_debugfs_show(struct seq_file *s, void *unused)

spin_lock_irqsave(&sync_timeline_list_lock, flags);
list_for_each(pos, &sync_timeline_list_head) {
- struct sync_timeline *obj =
- container_of(pos, struct sync_timeline,
- sync_timeline_list);
+ struct fence_timeline *obj =
+ container_of(pos, struct fence_timeline,
+ fence_timeline_list);

sync_print_obj(s, obj);
seq_puts(s, "\n");
@@ -251,7 +251,7 @@ static int sw_sync_debugfs_release(struct inode *inode, struct file *file)
{
struct sw_sync_timeline *obj = file->private_data;

- sync_timeline_destroy(&obj->obj);
+ fence_timeline_destroy(&obj->obj);
return 0;
}

diff --git a/drivers/staging/android/trace/sync.h b/drivers/staging/android/trace/sync.h
index 77edb97..59c337f 100644
--- a/drivers/staging/android/trace/sync.h
+++ b/drivers/staging/android/trace/sync.h
@@ -8,30 +8,6 @@
#include "../sync.h"
#include <linux/tracepoint.h>

-TRACE_EVENT(sync_timeline,
- TP_PROTO(struct sync_timeline *timeline),
-
- TP_ARGS(timeline),
-
- TP_STRUCT__entry(
- __string(name, timeline->name)
- __array(char, value, 32)
- ),
-
- TP_fast_assign(
- __assign_str(name, timeline->name);
- if (timeline->ops->timeline_value_str) {
- timeline->ops->timeline_value_str(timeline,
- __entry->value,
- sizeof(__entry->value));
- } else {
- __entry->value[0] = '\0';
- }
- ),
-
- TP_printk("name=%s value=%s", __get_str(name), __entry->value)
-);
-
TRACE_EVENT(sync_wait,
TP_PROTO(struct sync_fence *fence, int begin),

diff --git a/include/linux/fence.h b/include/linux/fence.h
index bb52201..a333bf37 100644
--- a/include/linux/fence.h
+++ b/include/linux/fence.h
@@ -30,9 +30,75 @@
#include <linux/printk.h>
#include <linux/rcupdate.h>

+struct fence_timeline;
struct fence;
struct fence_ops;
struct fence_cb;
+/**
+ * struct fence_timeline_ops - fence context implementation ops
+ * @driver_name: name of the implementation
+ * @has_signaled: returns:
+ * 1 if pt has signaled
+ * 0 if pt has not signaled
+ * <0 on error
+ * @fill_driver_data: write implementation specific driver data to data.
+ * should return an error if there is not enough room
+ * as specified by size. This information is returned
+ * to userspace by SYNC_IOC_FENCE_INFO.
+ * @timeline_value_str: fill str with the value of the sync_timeline's counter
+ * @pt_value_str: fill str with the value of the sync_pt
+ */
+struct fence_timeline_ops {
+ const char *driver_name;
+
+ /* required */
+ int (*has_signaled)(struct fence *fence);
+
+ /* optional */
+ int (*fill_driver_data)(struct fence *fence, void *data, int size);
+
+ /* optional */
+ void (*timeline_value_str)(struct fence_timeline *timeline, char *str,
+ int size);
+
+ /* optional */
+ void (*fence_value_str)(struct fence *fence, char *str, int size);
+};
+
+/**
+ * struct fence_timeline - timeline for software synchronization primitive
+ * @kref: refcount for timeline lifetime
+ * @name: name of the timeline
+ * @ops: pointer to fence_timeline_ops of users
+ * @detroyed: if true, the destroy process has started
+ * @value: value of the last signaled fence
+ * @child_list_head: list of child fences
+ * @active_list_head: list of active(not signaled) fences
+ * @lock: to protect lists access
+ * @fences: list of all timelines created
+ */
+struct fence_timeline {
+ struct kref kref;
+ char name[32];
+ const struct fence_timeline_ops *ops;
+ bool destroyed;
+ int value;
+ int context;
+ struct list_head child_list_head;
+ struct list_head active_list_head;
+ spinlock_t lock;
+#ifdef CONFIG_DEBUG_FS
+ struct list_head fence_timeline_list;
+#endif
+};
+
+struct fence_timeline *fence_timeline_create(unsigned num,
+ struct fence_timeline_ops *ops,
+ int size, const char *name);
+void fence_timeline_get(struct fence_timeline *timeline);
+void fence_timeline_put(struct fence_timeline *timeline);
+void fence_timeline_destroy(struct fence_timeline *timeline);
+void fence_timeline_signal(struct fence_timeline *timeline);

/**
* struct fence - software synchronization primitive
@@ -79,6 +145,8 @@ struct fence {
unsigned long flags;
ktime_t timestamp;
int status;
+ struct list_head child_list;
+ struct list_head active_list;
};

enum fence_flag_bits {
@@ -181,6 +249,13 @@ void fence_init(struct fence *fence, const struct fence_ops *ops,
void fence_release(struct kref *kref);
void fence_free(struct fence *fence);

+
+static inline struct fence_timeline *fence_parent(struct fence *fence)
+{
+ return container_of(fence->lock, struct fence_timeline,
+ lock);
+}
+
/**
* fence_get - increases refcount of the fence
* @fence: [in] fence to increase refcount of
diff --git a/include/trace/events/fence.h b/include/trace/events/fence.h
index 98feb1b..c4d01de 100644
--- a/include/trace/events/fence.h
+++ b/include/trace/events/fence.h
@@ -48,6 +48,30 @@ TRACE_EVENT(fence_annotate_wait_on,
__entry->waiting_context, __entry->waiting_seqno)
);

+TRACE_EVENT(fence_timeline,
+ TP_PROTO(struct fence_timeline *timeline),
+
+ TP_ARGS(timeline),
+
+ TP_STRUCT__entry(
+ __string(name, timeline->name)
+ __array(char, value, 32)
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, timeline->name);
+ if (timeline->ops->timeline_value_str) {
+ timeline->ops->timeline_value_str(timeline,
+ __entry->value,
+ sizeof(__entry->value));
+ } else {
+ __entry->value[0] = '\0';
+ }
+ ),
+
+ TP_printk("name=%s value=%s", __get_str(name), __entry->value)
+);
+
DECLARE_EVENT_CLASS(fence,

TP_PROTO(struct fence *fence),
--
2.5.0