diff mbox

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

Message ID 1452869739-3304-12-git-send-email-gustavo@padovan.org (mailing list archive)
State New, archived
Headers show

Commit Message

Gustavo Padovan Jan. 15, 2016, 2:55 p.m. UTC
From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>

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@collabora.co.uk>
---
 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(-)

Comments

Greg Hackmann Jan. 20, 2016, 12:56 a.m. UTC | #1
On 01/15/2016 06:55 AM, Gustavo Padovan wrote:
>   /**
> + * fence_timeline_create - create a new fence_timeline
> + * @num:	[in]	amount of contexts to allocate
[...]
> + */
> +struct fence_timeline *fence_timeline_create(unsigned num,
> +					     struct fence_timeline_ops *ops,
> +					     int size, const char *name)
> +{
[...]
> +	timeline->context = fence_context_alloc(1);

fence_context_alloc(num)
diff mbox

Patch

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),