blob: e671618cf888d60425b33873c7e5d3c8d4700716 [file] [log] [blame]
Lingfeng Yang1cbd16b2017-01-31 23:28:39 -08001#include <linux/slab.h>
2#include <linux/fs.h>
3#include <linux/syscalls.h>
4#include <linux/sync_file.h>
5#include <linux/fence.h>
6
7#include "goldfish_sync_timeline_fence.h"
8
9/*
10 * Timeline-based sync for Goldfish Sync
11 * Based on "Sync File validation framework"
12 * (drivers/dma-buf/sw_sync.c)
13 *
14 * Copyright (C) 2017 Google, Inc.
15 *
16 * This software is licensed under the terms of the GNU General Public
17 * License version 2, as published by the Free Software Foundation, and
18 * may be copied, distributed, and modified under those terms.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 */
26
27/**
28 * struct goldfish_sync_timeline - sync object
29 * @kref: reference count on fence.
30 * @name: name of the goldfish_sync_timeline. Useful for debugging
31 * @child_list_head: list of children sync_pts for this goldfish_sync_timeline
32 * @child_list_lock: lock protecting @child_list_head and fence.status
33 * @active_list_head: list of active (unsignaled/errored) sync_pts
34 */
35struct goldfish_sync_timeline {
36 struct kref kref;
37 char name[32];
38
39 /* protected by child_list_lock */
40 u64 context;
41 int value;
42
43 struct list_head child_list_head;
44 spinlock_t child_list_lock;
45
46 struct list_head active_list_head;
47};
48
49static inline struct goldfish_sync_timeline *fence_parent(struct fence *fence)
50{
51 return container_of(fence->lock, struct goldfish_sync_timeline,
52 child_list_lock);
53}
54
55static const struct fence_ops goldfish_sync_timeline_fence_ops;
56
57static inline struct sync_pt *goldfish_sync_fence_to_sync_pt(struct fence *fence)
58{
59 if (fence->ops != &goldfish_sync_timeline_fence_ops)
60 return NULL;
61 return container_of(fence, struct sync_pt, base);
62}
63
64/**
65 * goldfish_sync_timeline_create_internal() - creates a sync object
66 * @name: sync_timeline name
67 *
68 * Creates a new sync_timeline. Returns the sync_timeline object or NULL in
69 * case of error.
70 */
71struct goldfish_sync_timeline
72*goldfish_sync_timeline_create_internal(const char *name)
73{
74 struct goldfish_sync_timeline *obj;
75
76 obj = kzalloc(sizeof(*obj), GFP_KERNEL);
77 if (!obj)
78 return NULL;
79
80 kref_init(&obj->kref);
81 obj->context = fence_context_alloc(1);
82 strlcpy(obj->name, name, sizeof(obj->name));
83
84 INIT_LIST_HEAD(&obj->child_list_head);
85 INIT_LIST_HEAD(&obj->active_list_head);
86 spin_lock_init(&obj->child_list_lock);
87
88 return obj;
89}
90
91static void goldfish_sync_timeline_free_internal(struct kref *kref)
92{
93 struct goldfish_sync_timeline *obj =
94 container_of(kref, struct goldfish_sync_timeline, kref);
95
96 kfree(obj);
97}
98
99static void goldfish_sync_timeline_get_internal(
100 struct goldfish_sync_timeline *obj)
101{
102 kref_get(&obj->kref);
103}
104
105void goldfish_sync_timeline_put_internal(struct goldfish_sync_timeline *obj)
106{
107 kref_put(&obj->kref, goldfish_sync_timeline_free_internal);
108}
109
110/**
111 * goldfish_sync_timeline_signal() -
112 * signal a status change on a goldfish_sync_timeline
113 * @obj: sync_timeline to signal
114 * @inc: num to increment on timeline->value
115 *
116 * A sync implementation should call this any time one of it's fences
117 * has signaled or has an error condition.
118 */
119void goldfish_sync_timeline_signal_internal(struct goldfish_sync_timeline *obj,
120 unsigned int inc)
121{
122 unsigned long flags;
123 struct sync_pt *pt, *next;
124
125 spin_lock_irqsave(&obj->child_list_lock, flags);
126
127 obj->value += inc;
128
129 list_for_each_entry_safe(pt, next, &obj->active_list_head,
130 active_list) {
131 if (fence_is_signaled_locked(&pt->base))
132 list_del_init(&pt->active_list);
133 }
134
135 spin_unlock_irqrestore(&obj->child_list_lock, flags);
136}
137
138/**
139 * goldfish_sync_pt_create_internal() - creates a sync pt
140 * @parent: fence's parent sync_timeline
141 * @size: size to allocate for this pt
142 * @inc: value of the fence
143 *
144 * Creates a new sync_pt as a child of @parent. @size bytes will be
145 * allocated allowing for implementation specific data to be kept after
146 * the generic sync_timeline struct. Returns the sync_pt object or
147 * NULL in case of error.
148 */
149struct sync_pt *goldfish_sync_pt_create_internal(
150 struct goldfish_sync_timeline *obj, int size,
151 unsigned int value)
152{
153 unsigned long flags;
154 struct sync_pt *pt;
155
156 if (size < sizeof(*pt))
157 return NULL;
158
159 pt = kzalloc(size, GFP_KERNEL);
160 if (!pt)
161 return NULL;
162
163 spin_lock_irqsave(&obj->child_list_lock, flags);
164 goldfish_sync_timeline_get_internal(obj);
165 fence_init(&pt->base, &goldfish_sync_timeline_fence_ops, &obj->child_list_lock,
166 obj->context, value);
167 list_add_tail(&pt->child_list, &obj->child_list_head);
168 INIT_LIST_HEAD(&pt->active_list);
169 spin_unlock_irqrestore(&obj->child_list_lock, flags);
170 return pt;
171}
172
173static const char *goldfish_sync_timeline_fence_get_driver_name(
174 struct fence *fence)
175{
176 return "sw_sync";
177}
178
179static const char *goldfish_sync_timeline_fence_get_timeline_name(
180 struct fence *fence)
181{
182 struct goldfish_sync_timeline *parent = fence_parent(fence);
183
184 return parent->name;
185}
186
187static void goldfish_sync_timeline_fence_release(struct fence *fence)
188{
189 struct sync_pt *pt = goldfish_sync_fence_to_sync_pt(fence);
190 struct goldfish_sync_timeline *parent = fence_parent(fence);
191 unsigned long flags;
192
193 spin_lock_irqsave(fence->lock, flags);
194 list_del(&pt->child_list);
195 if (!list_empty(&pt->active_list))
196 list_del(&pt->active_list);
197 spin_unlock_irqrestore(fence->lock, flags);
198
199 goldfish_sync_timeline_put_internal(parent);
200 fence_free(fence);
201}
202
203static bool goldfish_sync_timeline_fence_signaled(struct fence *fence)
204{
205 struct goldfish_sync_timeline *parent = fence_parent(fence);
206
207 return (fence->seqno > parent->value) ? false : true;
208}
209
210static bool goldfish_sync_timeline_fence_enable_signaling(struct fence *fence)
211{
212 struct sync_pt *pt = goldfish_sync_fence_to_sync_pt(fence);
213 struct goldfish_sync_timeline *parent = fence_parent(fence);
214
215 if (goldfish_sync_timeline_fence_signaled(fence))
216 return false;
217
218 list_add_tail(&pt->active_list, &parent->active_list_head);
219 return true;
220}
221
222static void goldfish_sync_timeline_fence_disable_signaling(struct fence *fence)
223{
224 struct sync_pt *pt = container_of(fence, struct sync_pt, base);
225
226 list_del_init(&pt->active_list);
227}
228
229static void goldfish_sync_timeline_fence_value_str(struct fence *fence,
230 char *str, int size)
231{
232 snprintf(str, size, "%d", fence->seqno);
233}
234
235static void goldfish_sync_timeline_fence_timeline_value_str(
236 struct fence *fence,
237 char *str, int size)
238{
239 struct goldfish_sync_timeline *parent = fence_parent(fence);
240
241 snprintf(str, size, "%d", parent->value);
242}
243
244static const struct fence_ops goldfish_sync_timeline_fence_ops = {
245 .get_driver_name = goldfish_sync_timeline_fence_get_driver_name,
246 .get_timeline_name = goldfish_sync_timeline_fence_get_timeline_name,
247 .enable_signaling = goldfish_sync_timeline_fence_enable_signaling,
248 .disable_signaling = goldfish_sync_timeline_fence_disable_signaling,
249 .signaled = goldfish_sync_timeline_fence_signaled,
250 .wait = fence_default_wait,
251 .release = goldfish_sync_timeline_fence_release,
252 .fence_value_str = goldfish_sync_timeline_fence_value_str,
253 .timeline_value_str = goldfish_sync_timeline_fence_timeline_value_str,
254};