]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/staging/android/sync.c
block: Fix front merge check
[karo-tx-linux.git] / drivers / staging / android / sync.c
1 /*
2  * drivers/base/sync.c
3  *
4  * Copyright (C) 2012 Google, Inc.
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16
17 #include <linux/debugfs.h>
18 #include <linux/export.h>
19 #include <linux/kernel.h>
20 #include <linux/sched.h>
21 #include <linux/seq_file.h>
22 #include <linux/slab.h>
23 #include <linux/uaccess.h>
24 #include <linux/anon_inodes.h>
25
26 #include "sync.h"
27
28 #define CREATE_TRACE_POINTS
29 #include "trace/sync.h"
30
31 static const struct fence_ops android_fence_ops;
32
33 struct sync_timeline *sync_timeline_create(const struct sync_timeline_ops *ops,
34                                            int size, const char *name)
35 {
36         struct sync_timeline *obj;
37
38         if (size < sizeof(struct sync_timeline))
39                 return NULL;
40
41         obj = kzalloc(size, GFP_KERNEL);
42         if (!obj)
43                 return NULL;
44
45         kref_init(&obj->kref);
46         obj->ops = ops;
47         obj->context = fence_context_alloc(1);
48         strlcpy(obj->name, name, sizeof(obj->name));
49
50         INIT_LIST_HEAD(&obj->child_list_head);
51         INIT_LIST_HEAD(&obj->active_list_head);
52         spin_lock_init(&obj->child_list_lock);
53
54         sync_timeline_debug_add(obj);
55
56         return obj;
57 }
58 EXPORT_SYMBOL(sync_timeline_create);
59
60 static void sync_timeline_free(struct kref *kref)
61 {
62         struct sync_timeline *obj =
63                 container_of(kref, struct sync_timeline, kref);
64
65         sync_timeline_debug_remove(obj);
66
67         kfree(obj);
68 }
69
70 static void sync_timeline_get(struct sync_timeline *obj)
71 {
72         kref_get(&obj->kref);
73 }
74
75 static void sync_timeline_put(struct sync_timeline *obj)
76 {
77         kref_put(&obj->kref, sync_timeline_free);
78 }
79
80 void sync_timeline_destroy(struct sync_timeline *obj)
81 {
82         obj->destroyed = true;
83         /*
84          * Ensure timeline is marked as destroyed before
85          * changing timeline's fences status.
86          */
87         smp_wmb();
88
89         sync_timeline_put(obj);
90 }
91 EXPORT_SYMBOL(sync_timeline_destroy);
92
93 void sync_timeline_signal(struct sync_timeline *obj)
94 {
95         unsigned long flags;
96         struct fence *fence, *next;
97
98         trace_sync_timeline(obj);
99
100         spin_lock_irqsave(&obj->child_list_lock, flags);
101
102         list_for_each_entry_safe(fence, next, &obj->active_list_head,
103                                  active_list) {
104                 if (fence_is_signaled_locked(fence))
105                         list_del_init(&fence->active_list);
106         }
107
108         spin_unlock_irqrestore(&obj->child_list_lock, flags);
109 }
110 EXPORT_SYMBOL(sync_timeline_signal);
111
112 struct fence *sync_pt_create(struct sync_timeline *obj, int size)
113 {
114         unsigned long flags;
115         struct fence *fence;
116
117         if (size < sizeof(*fence))
118                 return NULL;
119
120         fence = kzalloc(size, GFP_KERNEL);
121         if (!fence)
122                 return NULL;
123
124         spin_lock_irqsave(&obj->child_list_lock, flags);
125         sync_timeline_get(obj);
126         fence_init(fence, &android_fence_ops, &obj->child_list_lock,
127                    obj->context, ++obj->value);
128         list_add_tail(&fence->child_list, &obj->child_list_head);
129         INIT_LIST_HEAD(&fence->active_list);
130         spin_unlock_irqrestore(&obj->child_list_lock, flags);
131         return fence;
132 }
133 EXPORT_SYMBOL(sync_pt_create);
134
135 static const char *android_fence_get_driver_name(struct fence *fence)
136 {
137         struct sync_timeline *parent = fence_parent(fence);
138
139         return parent->ops->driver_name;
140 }
141
142 static const char *android_fence_get_timeline_name(struct fence *fence)
143 {
144         struct sync_timeline *parent = fence_parent(fence);
145
146         return parent->name;
147 }
148
149 static void android_fence_release(struct fence *fence)
150 {
151         struct sync_timeline *parent = fence_parent(fence);
152         unsigned long flags;
153
154         spin_lock_irqsave(fence->lock, flags);
155         list_del(&fence->child_list);
156         if (WARN_ON_ONCE(!list_empty(&fence->active_list)))
157                 list_del(&fence->active_list);
158         spin_unlock_irqrestore(fence->lock, flags);
159
160         sync_timeline_put(parent);
161         fence_free(fence);
162 }
163
164 static bool android_fence_signaled(struct fence *fence)
165 {
166         struct sync_timeline *parent = fence_parent(fence);
167         int ret;
168
169         ret = parent->ops->has_signaled(fence);
170         if (ret < 0)
171                 fence->status = ret;
172         return ret;
173 }
174
175 static bool android_fence_enable_signaling(struct fence *fence)
176 {
177         struct sync_timeline *parent = fence_parent(fence);
178
179         if (android_fence_signaled(fence))
180                 return false;
181
182         list_add_tail(&fence->active_list, &parent->active_list_head);
183         return true;
184 }
185
186 static void android_fence_value_str(struct fence *fence,
187                                     char *str, int size)
188 {
189         struct sync_timeline *parent = fence_parent(fence);
190
191         if (!parent->ops->fence_value_str) {
192                 if (size)
193                         *str = 0;
194                 return;
195         }
196         parent->ops->fence_value_str(fence, str, size);
197 }
198
199 static void android_fence_timeline_value_str(struct fence *fence,
200                                              char *str, int size)
201 {
202         struct sync_timeline *parent = fence_parent(fence);
203
204         if (!parent->ops->timeline_value_str) {
205                 if (size)
206                         *str = 0;
207                 return;
208         }
209         parent->ops->timeline_value_str(parent, str, size);
210 }
211
212 static const struct fence_ops android_fence_ops = {
213         .get_driver_name = android_fence_get_driver_name,
214         .get_timeline_name = android_fence_get_timeline_name,
215         .enable_signaling = android_fence_enable_signaling,
216         .signaled = android_fence_signaled,
217         .wait = fence_default_wait,
218         .release = android_fence_release,
219         .fence_value_str = android_fence_value_str,
220         .timeline_value_str = android_fence_timeline_value_str,
221 };