Commit | Line | Data |
---|---|---|
7ad530bf EG |
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 | ||
af7582f2 | 17 | #include <linux/debugfs.h> |
8edb4ad9 | 18 | #include <linux/export.h> |
7ad530bf EG |
19 | #include <linux/kernel.h> |
20 | #include <linux/sched.h> | |
af7582f2 | 21 | #include <linux/seq_file.h> |
7ad530bf EG |
22 | #include <linux/slab.h> |
23 | #include <linux/uaccess.h> | |
24 | #include <linux/anon_inodes.h> | |
25 | ||
26 | #include "sync.h" | |
27 | ||
b699a644 EG |
28 | #define CREATE_TRACE_POINTS |
29 | #include "trace/sync.h" | |
30 | ||
0f0d8406 | 31 | static const struct fence_ops android_fence_ops; |
af7582f2 | 32 | |
7ad530bf EG |
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); | |
375fb53e | 42 | if (!obj) |
7ad530bf EG |
43 | return NULL; |
44 | ||
c5b86b74 | 45 | kref_init(&obj->kref); |
7ad530bf | 46 | obj->ops = ops; |
0f0d8406 | 47 | obj->context = fence_context_alloc(1); |
7ad530bf EG |
48 | strlcpy(obj->name, name, sizeof(obj->name)); |
49 | ||
50 | INIT_LIST_HEAD(&obj->child_list_head); | |
7ad530bf | 51 | INIT_LIST_HEAD(&obj->active_list_head); |
0f0d8406 | 52 | spin_lock_init(&obj->child_list_lock); |
7ad530bf | 53 | |
0f0d8406 | 54 | sync_timeline_debug_add(obj); |
af7582f2 | 55 | |
7ad530bf EG |
56 | return obj; |
57 | } | |
8edb4ad9 | 58 | EXPORT_SYMBOL(sync_timeline_create); |
7ad530bf | 59 | |
c5b86b74 | 60 | static void sync_timeline_free(struct kref *kref) |
af7582f2 | 61 | { |
c5b86b74 EG |
62 | struct sync_timeline *obj = |
63 | container_of(kref, struct sync_timeline, kref); | |
af7582f2 | 64 | |
0f0d8406 | 65 | sync_timeline_debug_remove(obj); |
af7582f2 EG |
66 | |
67 | kfree(obj); | |
68 | } | |
69 | ||
0f0d8406 ML |
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 | ||
7ad530bf EG |
80 | void sync_timeline_destroy(struct sync_timeline *obj) |
81 | { | |
7ad530bf | 82 | obj->destroyed = true; |
29606609 NY |
83 | /* |
84 | * Ensure timeline is marked as destroyed before | |
85 | * changing timeline's fences status. | |
86 | */ | |
ac5b705b | 87 | smp_wmb(); |
7ad530bf | 88 | |
0f0d8406 | 89 | sync_timeline_put(obj); |
7ad530bf | 90 | } |
8edb4ad9 | 91 | EXPORT_SYMBOL(sync_timeline_destroy); |
7ad530bf | 92 | |
7ad530bf EG |
93 | void sync_timeline_signal(struct sync_timeline *obj) |
94 | { | |
95 | unsigned long flags; | |
b55b54b5 | 96 | struct fence *fence, *next; |
7ad530bf | 97 | |
b699a644 EG |
98 | trace_sync_timeline(obj); |
99 | ||
0f0d8406 | 100 | spin_lock_irqsave(&obj->child_list_lock, flags); |
7ad530bf | 101 | |
b55b54b5 | 102 | list_for_each_entry_safe(fence, next, &obj->active_list_head, |
0f0d8406 | 103 | active_list) { |
b55b54b5 GP |
104 | if (fence_is_signaled_locked(fence)) |
105 | list_del_init(&fence->active_list); | |
7ad530bf EG |
106 | } |
107 | ||
0f0d8406 | 108 | spin_unlock_irqrestore(&obj->child_list_lock, flags); |
7ad530bf | 109 | } |
8edb4ad9 | 110 | EXPORT_SYMBOL(sync_timeline_signal); |
7ad530bf | 111 | |
b55b54b5 | 112 | struct fence *sync_pt_create(struct sync_timeline *obj, int size) |
7ad530bf | 113 | { |
0f0d8406 | 114 | unsigned long flags; |
b55b54b5 | 115 | struct fence *fence; |
7ad530bf | 116 | |
b55b54b5 | 117 | if (size < sizeof(*fence)) |
7ad530bf EG |
118 | return NULL; |
119 | ||
b55b54b5 GP |
120 | fence = kzalloc(size, GFP_KERNEL); |
121 | if (!fence) | |
7ad530bf EG |
122 | return NULL; |
123 | ||
0f0d8406 ML |
124 | spin_lock_irqsave(&obj->child_list_lock, flags); |
125 | sync_timeline_get(obj); | |
b55b54b5 | 126 | fence_init(fence, &android_fence_ops, &obj->child_list_lock, |
0f0d8406 | 127 | obj->context, ++obj->value); |
b55b54b5 GP |
128 | list_add_tail(&fence->child_list, &obj->child_list_head); |
129 | INIT_LIST_HEAD(&fence->active_list); | |
0f0d8406 | 130 | spin_unlock_irqrestore(&obj->child_list_lock, flags); |
b55b54b5 | 131 | return fence; |
7ad530bf | 132 | } |
8edb4ad9 | 133 | EXPORT_SYMBOL(sync_pt_create); |
7ad530bf | 134 | |
0f0d8406 ML |
135 | static const char *android_fence_get_driver_name(struct fence *fence) |
136 | { | |
b55b54b5 | 137 | struct sync_timeline *parent = fence_parent(fence); |
0f0d8406 ML |
138 | |
139 | return parent->ops->driver_name; | |
140 | } | |
141 | ||
142 | static const char *android_fence_get_timeline_name(struct fence *fence) | |
143 | { | |
b55b54b5 | 144 | struct sync_timeline *parent = fence_parent(fence); |
0f0d8406 ML |
145 | |
146 | return parent->name; | |
147 | } | |
148 | ||
149 | static void android_fence_release(struct fence *fence) | |
150 | { | |
b55b54b5 | 151 | struct sync_timeline *parent = fence_parent(fence); |
0f0d8406 ML |
152 | unsigned long flags; |
153 | ||
154 | spin_lock_irqsave(fence->lock, flags); | |
b55b54b5 GP |
155 | list_del(&fence->child_list); |
156 | if (WARN_ON_ONCE(!list_empty(&fence->active_list))) | |
157 | list_del(&fence->active_list); | |
0f0d8406 ML |
158 | spin_unlock_irqrestore(fence->lock, flags); |
159 | ||
0f0d8406 | 160 | sync_timeline_put(parent); |
b55b54b5 | 161 | fence_free(fence); |
0f0d8406 ML |
162 | } |
163 | ||
164 | static bool android_fence_signaled(struct fence *fence) | |
165 | { | |
b55b54b5 | 166 | struct sync_timeline *parent = fence_parent(fence); |
0f0d8406 ML |
167 | int ret; |
168 | ||
b55b54b5 | 169 | ret = parent->ops->has_signaled(fence); |
0f0d8406 ML |
170 | if (ret < 0) |
171 | fence->status = ret; | |
172 | return ret; | |
173 | } | |
174 | ||
175 | static bool android_fence_enable_signaling(struct fence *fence) | |
176 | { | |
b55b54b5 | 177 | struct sync_timeline *parent = fence_parent(fence); |
0f0d8406 ML |
178 | |
179 | if (android_fence_signaled(fence)) | |
180 | return false; | |
181 | ||
b55b54b5 | 182 | list_add_tail(&fence->active_list, &parent->active_list_head); |
0f0d8406 ML |
183 | return true; |
184 | } | |
185 | ||
0f0d8406 ML |
186 | static void android_fence_value_str(struct fence *fence, |
187 | char *str, int size) | |
188 | { | |
b55b54b5 | 189 | struct sync_timeline *parent = fence_parent(fence); |
0f0d8406 | 190 | |
b55b54b5 | 191 | if (!parent->ops->fence_value_str) { |
0f0d8406 ML |
192 | if (size) |
193 | *str = 0; | |
194 | return; | |
195 | } | |
b55b54b5 | 196 | parent->ops->fence_value_str(fence, str, size); |
0f0d8406 ML |
197 | } |
198 | ||
199 | static void android_fence_timeline_value_str(struct fence *fence, | |
200 | char *str, int size) | |
201 | { | |
b55b54b5 | 202 | struct sync_timeline *parent = fence_parent(fence); |
0f0d8406 ML |
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, | |
0f0d8406 ML |
219 | .fence_value_str = android_fence_value_str, |
220 | .timeline_value_str = android_fence_timeline_value_str, | |
221 | }; |