On 02/17/2014 04:57 PM, Maarten Lankhorst wrote: > Android syncpoints can be mapped to a timeline. This removes the need > to maintain a separate api for synchronization. I've left the android > trace events in place, but the core fence events should already be > sufficient for debugging. > > v2: > - Call fence_remove_callback in sync_fence_free if not all fences have fired. > v3: > - Merge Colin Cross' bugfixes, and the android fence merge optimization. > v4: > - Merge with the upstream fixes. > > Signed-off-by: Maarten Lankhorst <maarten.lankhorst@xxxxxxxxxxxxx> > --- > drivers/staging/android/Kconfig | 1 > drivers/staging/android/Makefile | 2 > drivers/staging/android/sw_sync.c | 4 > drivers/staging/android/sync.c | 892 +++++++++++----------------------- > drivers/staging/android/sync.h | 80 ++- > drivers/staging/android/sync_debug.c | 245 +++++++++ > drivers/staging/android/trace/sync.h | 12 > 7 files changed, 592 insertions(+), 644 deletions(-) > create mode 100644 drivers/staging/android/sync_debug.c > > diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig > index b91c758883bf..ecc8194242b5 100644 > --- a/drivers/staging/android/Kconfig > +++ b/drivers/staging/android/Kconfig > @@ -77,6 +77,7 @@ config SYNC > bool "Synchronization framework" > default n > select ANON_INODES > + select DMA_SHARED_BUFFER > ---help--- > This option enables the framework for synchronization between multiple > drivers. Sync implementations can take advantage of hardware > diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile > index 0a01e1914905..517ad5ffa429 100644 > --- a/drivers/staging/android/Makefile > +++ b/drivers/staging/android/Makefile > @@ -9,5 +9,5 @@ obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o > obj-$(CONFIG_ANDROID_TIMED_GPIO) += timed_gpio.o > obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o > obj-$(CONFIG_ANDROID_INTF_ALARM_DEV) += alarm-dev.o > -obj-$(CONFIG_SYNC) += sync.o > +obj-$(CONFIG_SYNC) += sync.o sync_debug.o > obj-$(CONFIG_SW_SYNC) += sw_sync.o > diff --git a/drivers/staging/android/sw_sync.c b/drivers/staging/android/sw_sync.c > index f24493ac65e3..a76db3ff87cb 100644 > --- a/drivers/staging/android/sw_sync.c > +++ b/drivers/staging/android/sw_sync.c > @@ -50,7 +50,7 @@ static struct sync_pt *sw_sync_pt_dup(struct sync_pt *sync_pt) > { > struct sw_sync_pt *pt = (struct sw_sync_pt *) sync_pt; > struct sw_sync_timeline *obj = > - (struct sw_sync_timeline *)sync_pt->parent; > + (struct sw_sync_timeline *)sync_pt_parent(sync_pt); > > return (struct sync_pt *) sw_sync_pt_create(obj, pt->value); > } > @@ -59,7 +59,7 @@ static int sw_sync_pt_has_signaled(struct sync_pt *sync_pt) > { > struct sw_sync_pt *pt = (struct sw_sync_pt *)sync_pt; > struct sw_sync_timeline *obj = > - (struct sw_sync_timeline *)sync_pt->parent; > + (struct sw_sync_timeline *)sync_pt_parent(sync_pt); > > return sw_sync_cmp(obj->value, pt->value) >= 0; > } > diff --git a/drivers/staging/android/sync.c b/drivers/staging/android/sync.c > index 3d05f662110b..8e77cd73b739 100644 > --- a/drivers/staging/android/sync.c > +++ b/drivers/staging/android/sync.c > @@ -31,22 +31,13 @@ > #define CREATE_TRACE_POINTS > #include "trace/sync.h" > > -static void sync_fence_signal_pt(struct sync_pt *pt); > -static int _sync_pt_has_signaled(struct sync_pt *pt); > -static void sync_fence_free(struct kref *kref); > -static void sync_dump(void); > - > -static LIST_HEAD(sync_timeline_list_head); > -static DEFINE_SPINLOCK(sync_timeline_list_lock); > - > -static LIST_HEAD(sync_fence_list_head); > -static DEFINE_SPINLOCK(sync_fence_list_lock); > +static const struct fence_ops android_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; > - unsigned long flags; > > if (size < sizeof(struct sync_timeline)) > return NULL; > @@ -57,17 +48,14 @@ struct sync_timeline *sync_timeline_create(const struct sync_timeline_ops *ops, > > 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); > - spin_lock_init(&obj->child_list_lock); > - > INIT_LIST_HEAD(&obj->active_list_head); > - spin_lock_init(&obj->active_list_lock); > + spin_lock_init(&obj->child_list_lock); > > - spin_lock_irqsave(&sync_timeline_list_lock, flags); > - list_add_tail(&obj->sync_timeline_list, &sync_timeline_list_head); > - spin_unlock_irqrestore(&sync_timeline_list_lock, flags); > + sync_timeline_debug_add(obj); > > return obj; > } > @@ -77,11 +65,8 @@ static void sync_timeline_free(struct kref *kref) > { > struct sync_timeline *obj = > container_of(kref, struct sync_timeline, kref); > - unsigned long flags; > > - spin_lock_irqsave(&sync_timeline_list_lock, flags); > - list_del(&obj->sync_timeline_list); > - spin_unlock_irqrestore(&sync_timeline_list_lock, flags); > + sync_timeline_debug_remove(obj); > > if (obj->ops->release_obj) > obj->ops->release_obj(obj); > @@ -89,6 +74,16 @@ static void sync_timeline_free(struct kref *kref) > 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; > @@ -98,75 +93,30 @@ void sync_timeline_destroy(struct sync_timeline *obj) > * signal any children that their parent is going away. > */ > sync_timeline_signal(obj); > - > - kref_put(&obj->kref, sync_timeline_free); > + sync_timeline_put(obj); > } > EXPORT_SYMBOL(sync_timeline_destroy); > > -static void sync_timeline_add_pt(struct sync_timeline *obj, struct sync_pt *pt) > -{ > - unsigned long flags; > - > - pt->parent = obj; > - > - spin_lock_irqsave(&obj->child_list_lock, flags); > - list_add_tail(&pt->child_list, &obj->child_list_head); > - spin_unlock_irqrestore(&obj->child_list_lock, flags); > -} > - > -static void sync_timeline_remove_pt(struct sync_pt *pt) > -{ > - struct sync_timeline *obj = pt->parent; > - unsigned long flags; > - > - spin_lock_irqsave(&obj->active_list_lock, flags); > - if (!list_empty(&pt->active_list)) > - list_del_init(&pt->active_list); > - spin_unlock_irqrestore(&obj->active_list_lock, flags); > - > - spin_lock_irqsave(&obj->child_list_lock, flags); > - if (!list_empty(&pt->child_list)) > - list_del_init(&pt->child_list); > - > - spin_unlock_irqrestore(&obj->child_list_lock, flags); > -} > - > void sync_timeline_signal(struct sync_timeline *obj) > { > unsigned long flags; > LIST_HEAD(signaled_pts); > - struct list_head *pos, *n; > + struct sync_pt *pt, *next; > > trace_sync_timeline(obj); > > - spin_lock_irqsave(&obj->active_list_lock, flags); > - > - list_for_each_safe(pos, n, &obj->active_list_head) { > - struct sync_pt *pt = > - container_of(pos, struct sync_pt, active_list); > - > - if (_sync_pt_has_signaled(pt)) { > - list_del_init(pos); > - list_add(&pt->signaled_list, &signaled_pts); > - kref_get(&pt->fence->kref); > - } > - } > - > - spin_unlock_irqrestore(&obj->active_list_lock, flags); > - > - list_for_each_safe(pos, n, &signaled_pts) { > - struct sync_pt *pt = > - container_of(pos, struct sync_pt, signaled_list); > - > - list_del_init(pos); > - sync_fence_signal_pt(pt); > - kref_put(&pt->fence->kref, sync_fence_free); > + 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(&pt->base)) > + list_del(&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 *parent, int size) > +struct sync_pt *sync_pt_create(struct sync_timeline *obj, int size) > { > + unsigned long flags; > struct sync_pt *pt; > > if (size < sizeof(struct sync_pt)) > @@ -176,87 +126,27 @@ struct sync_pt *sync_pt_create(struct sync_timeline *parent, int size) > if (pt == NULL) > return NULL; > > + spin_lock_irqsave(&obj->child_list_lock, flags); > + sync_timeline_get(obj); > + __fence_init(&pt->base, &android_fence_ops, &obj->child_list_lock, obj->context, ++obj->value); > + list_add_tail(&pt->child_list, &obj->child_list_head); > INIT_LIST_HEAD(&pt->active_list); > - kref_get(&parent->kref); > - sync_timeline_add_pt(parent, pt); > - > + spin_unlock_irqrestore(&obj->child_list_lock, flags); > return pt; > } > EXPORT_SYMBOL(sync_pt_create); > > void sync_pt_free(struct sync_pt *pt) > { > - if (pt->parent->ops->free_pt) > - pt->parent->ops->free_pt(pt); > - > - sync_timeline_remove_pt(pt); > - > - kref_put(&pt->parent->kref, sync_timeline_free); > - > - kfree(pt); > + fence_put(&pt->base); > } > EXPORT_SYMBOL(sync_pt_free); > > -/* call with pt->parent->active_list_lock held */ > -static int _sync_pt_has_signaled(struct sync_pt *pt) > -{ > - int old_status = pt->status; > - > - if (!pt->status) > - pt->status = pt->parent->ops->has_signaled(pt); > - > - if (!pt->status && pt->parent->destroyed) > - pt->status = -ENOENT; > - > - if (pt->status != old_status) > - pt->timestamp = ktime_get(); > - > - return pt->status; > -} > - > -static struct sync_pt *sync_pt_dup(struct sync_pt *pt) > -{ > - return pt->parent->ops->dup(pt); > -} > - > -/* Adds a sync pt to the active queue. Called when added to a fence */ > -static void sync_pt_activate(struct sync_pt *pt) > -{ > - struct sync_timeline *obj = pt->parent; > - unsigned long flags; > - int err; > - > - spin_lock_irqsave(&obj->active_list_lock, flags); > - > - err = _sync_pt_has_signaled(pt); > - if (err != 0) > - goto out; > - > - list_add_tail(&pt->active_list, &obj->active_list_head); > - > -out: > - spin_unlock_irqrestore(&obj->active_list_lock, flags); > -} > - > -static int sync_fence_release(struct inode *inode, struct file *file); > -static unsigned int sync_fence_poll(struct file *file, poll_table *wait); > -static long sync_fence_ioctl(struct file *file, unsigned int cmd, > - unsigned long arg); > - > - > -static const struct file_operations sync_fence_fops = { > - .release = sync_fence_release, > - .poll = sync_fence_poll, > - .unlocked_ioctl = sync_fence_ioctl, > - .compat_ioctl = sync_fence_ioctl, > -}; > - > -static struct sync_fence *sync_fence_alloc(const char *name) > +static struct sync_fence *sync_fence_alloc(int size, const char *name) > { > struct sync_fence *fence; > - unsigned long flags; > > - fence = kzalloc(sizeof(struct sync_fence), GFP_KERNEL); > + fence = kzalloc(size, GFP_KERNEL); > if (fence == NULL) > return NULL; > > @@ -268,16 +158,8 @@ static struct sync_fence *sync_fence_alloc(const char *name) > kref_init(&fence->kref); > strlcpy(fence->name, name, sizeof(fence->name)); > > - INIT_LIST_HEAD(&fence->pt_list_head); > - INIT_LIST_HEAD(&fence->waiter_list_head); > - spin_lock_init(&fence->waiter_list_lock); > - > init_waitqueue_head(&fence->wq); > > - spin_lock_irqsave(&sync_fence_list_lock, flags); > - list_add_tail(&fence->sync_fence_list, &sync_fence_list_head); > - spin_unlock_irqrestore(&sync_fence_list_lock, flags); > - > return fence; > > err: > @@ -285,119 +167,40 @@ err: > return NULL; > } > > +static void fence_check_cb_func(struct fence *f, struct fence_cb *cb) > +{ > + struct sync_fence_cb *check = container_of(cb, struct sync_fence_cb, cb); > + struct sync_fence *fence = check->fence; > + > + // TODO: Add a fence->status member and check it Hmm, C++ / C99 style comments makes checkpatch.pl complain. Did you run this series through checkpatch? /Thomas -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html