Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[deliverable/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 };
This page took 0.068174 seconds and 5 git commands to generate.