From patchwork Fri Jan 15 14:55:21 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gustavo Padovan X-Patchwork-Id: 8041841 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 86A05BEEE1 for ; Fri, 15 Jan 2016 14:56:34 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 904CA20384 for ; Fri, 15 Jan 2016 14:56:31 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id E751B2044B for ; Fri, 15 Jan 2016 14:56:28 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 08DA77A0EC; Fri, 15 Jan 2016 06:56:28 -0800 (PST) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mail-yk0-f178.google.com (mail-yk0-f178.google.com [209.85.160.178]) by gabe.freedesktop.org (Postfix) with ESMTPS id 607557A0EF for ; Fri, 15 Jan 2016 06:56:26 -0800 (PST) Received: by mail-yk0-f178.google.com with SMTP id k129so522511311yke.0 for ; Fri, 15 Jan 2016 06:56:26 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=F61bFjyj5YWbYkAlp8YQEXh9UlyaC96oGkO7EcPU09Q=; b=bglwWZkiMmBNWt+UcUSDZfTuNBV4lKsw25ojULWf0BofN/uuW3KxDEnp/3dVXmYBGL UjjCXsclBETqS8fW2GOsuI7A4swVz24xPCpIvXTA9eeiZu6TwN0JcdsokM0HQFj4ZZ9o edaW+yIZUB4cNq4VCJKpJ9K9i8ZNt5UVmYPDS8QAA6dPovjhPjEP4UgOw/nAcAV03y0x fVGp17kiGN9LAzK+EjhXgOdaY6TApWymaXAltM5Z8KmkgCJLKvh2GX6A2gmrciSRCIei rzXqfxDVR9dAlUK0SvsUZI0KbGJHvu5ABLzRcpk71ZnIdtCu15VEAxstH/ncbaRpVYZk n5wg== X-Gm-Message-State: ALoCoQnd3OsB7+rEZbaaRSe5JLc11v8DjEYxwwBybMawOCtSLK44n0OUKYZ2vzOxuZJtVJgKkFG6WUH9JJsSYk4CBOVFnYZ4zw== X-Received: by 10.37.19.65 with SMTP id 62mr964319ybt.177.1452869785694; Fri, 15 Jan 2016 06:56:25 -0800 (PST) Received: from jade.localdomain ([2804:14c:487:41f:6257:18ff:feab:2e8f]) by smtp.gmail.com with ESMTPSA id o123sm8267717ywd.2.2016.01.15.06.56.21 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 15 Jan 2016 06:56:25 -0800 (PST) From: Gustavo Padovan To: Greg Kroah-Hartman Subject: [RFC 11/29] dma-buf/fence: move sync_timeline to fence_timeline Date: Fri, 15 Jan 2016 12:55:21 -0200 Message-Id: <1452869739-3304-12-git-send-email-gustavo@padovan.org> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1452869739-3304-1-git-send-email-gustavo@padovan.org> References: <1452869739-3304-1-git-send-email-gustavo@padovan.org> Cc: devel@driverdev.osuosl.org, daniels@collabora.com, Daniel Vetter , Riley Andrews , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?= , Maarten Lankhorst , Gustavo Padovan , John Harrison X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Gustavo Padovan 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 --- 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 -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 #include +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),