blob: 973a2ff243f9304fec261d362a4329ea97a4fc63 [file] [log] [blame]
Shrenuj Bansala419c792016-10-20 14:05:11 -07001/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/err.h>
15#include <linux/file.h>
16#include <linux/sched.h>
17#include <linux/slab.h>
18#include <linux/uaccess.h>
19
20#include <asm/current.h>
21
22#include "kgsl_sync.h"
23
Lynus Vazc031a9b2017-01-25 13:00:13 +053024static void kgsl_sync_timeline_signal(struct kgsl_sync_timeline *timeline,
Shrenuj Bansala419c792016-10-20 14:05:11 -070025 unsigned int timestamp);
26
Lynus Vazc031a9b2017-01-25 13:00:13 +053027static const struct fence_ops kgsl_sync_fence_ops;
28
29static struct kgsl_sync_fence *kgsl_sync_fence_create(
30 struct kgsl_context *context,
31 unsigned int timestamp)
Shrenuj Bansala419c792016-10-20 14:05:11 -070032{
Lynus Vazc031a9b2017-01-25 13:00:13 +053033 struct kgsl_sync_fence *kfence;
34 struct kgsl_sync_timeline *ktimeline = context->ktimeline;
35 unsigned long flags;
Shrenuj Bansala419c792016-10-20 14:05:11 -070036
Lynus Vazc031a9b2017-01-25 13:00:13 +053037 /* Get a refcount to the timeline. Put when released */
38 if (!kref_get_unless_zero(&ktimeline->kref))
39 return NULL;
Shrenuj Bansala419c792016-10-20 14:05:11 -070040
Lynus Vazc031a9b2017-01-25 13:00:13 +053041 kfence = kzalloc(sizeof(*kfence), GFP_KERNEL);
42 if (kfence == NULL) {
43 kgsl_sync_timeline_put(ktimeline);
44 KGSL_DRV_ERR(context->device, "Couldn't allocate fence\n");
45 return NULL;
Shrenuj Bansala419c792016-10-20 14:05:11 -070046 }
Lynus Vazc031a9b2017-01-25 13:00:13 +053047
48 kfence->parent = ktimeline;
49 kfence->context_id = context->id;
50 kfence->timestamp = timestamp;
51
52 fence_init(&kfence->fence, &kgsl_sync_fence_ops, &ktimeline->lock,
53 ktimeline->fence_context, timestamp);
54
55 kfence->sync_file = sync_file_create(&kfence->fence);
56
57 if (kfence->sync_file == NULL) {
58 kgsl_sync_timeline_put(ktimeline);
59 KGSL_DRV_ERR(context->device, "Create sync_file failed\n");
60 kfree(kfence);
61 return NULL;
62 }
63
64 /* Get a refcount to the fence. Put when signaled */
65 fence_get(&kfence->fence);
66
67 spin_lock_irqsave(&ktimeline->lock, flags);
68 list_add_tail(&kfence->child_list, &ktimeline->child_list_head);
69 spin_unlock_irqrestore(&ktimeline->lock, flags);
70
71 return kfence;
Shrenuj Bansala419c792016-10-20 14:05:11 -070072}
73
Lynus Vazc031a9b2017-01-25 13:00:13 +053074static void kgsl_sync_fence_release(struct fence *fence)
Shrenuj Bansala419c792016-10-20 14:05:11 -070075{
Lynus Vazc031a9b2017-01-25 13:00:13 +053076 struct kgsl_sync_fence *kfence = (struct kgsl_sync_fence *)fence;
77
78 kgsl_sync_timeline_put(kfence->parent);
79 kfree(kfence);
Shrenuj Bansala419c792016-10-20 14:05:11 -070080}
81
Lynus Vazc031a9b2017-01-25 13:00:13 +053082/* Called with ktimeline->lock held */
83bool kgsl_sync_fence_has_signaled(struct fence *fence)
Shrenuj Bansala419c792016-10-20 14:05:11 -070084{
Lynus Vazc031a9b2017-01-25 13:00:13 +053085 struct kgsl_sync_fence *kfence = (struct kgsl_sync_fence *)fence;
86 struct kgsl_sync_timeline *ktimeline = kfence->parent;
87 unsigned int ts = kfence->timestamp;
Shrenuj Bansala419c792016-10-20 14:05:11 -070088
Lynus Vazc031a9b2017-01-25 13:00:13 +053089 return (timestamp_cmp(ktimeline->last_timestamp, ts) >= 0);
Shrenuj Bansala419c792016-10-20 14:05:11 -070090}
91
Lynus Vazc031a9b2017-01-25 13:00:13 +053092bool kgsl_enable_signaling(struct fence *fence)
Shrenuj Bansala419c792016-10-20 14:05:11 -070093{
Lynus Vazc031a9b2017-01-25 13:00:13 +053094 return !kgsl_sync_fence_has_signaled(fence);
Shrenuj Bansala419c792016-10-20 14:05:11 -070095}
96
Lynus Vazc031a9b2017-01-25 13:00:13 +053097struct kgsl_sync_fence_event_priv {
Shrenuj Bansala419c792016-10-20 14:05:11 -070098 struct kgsl_context *context;
99 unsigned int timestamp;
100};
101
102/**
Lynus Vazc031a9b2017-01-25 13:00:13 +0530103 * kgsl_sync_fence_event_cb - Event callback for a fence timestamp event
Shrenuj Bansala419c792016-10-20 14:05:11 -0700104 * @device - The KGSL device that expired the timestamp
105 * @context- Pointer to the context that owns the event
106 * @priv: Private data for the callback
107 * @result - Result of the event (retired or canceled)
108 *
109 * Signal a fence following the expiration of a timestamp
110 */
111
Lynus Vazc031a9b2017-01-25 13:00:13 +0530112static void kgsl_sync_fence_event_cb(struct kgsl_device *device,
Shrenuj Bansala419c792016-10-20 14:05:11 -0700113 struct kgsl_event_group *group, void *priv, int result)
114{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530115 struct kgsl_sync_fence_event_priv *ev = priv;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700116
Lynus Vazc031a9b2017-01-25 13:00:13 +0530117 kgsl_sync_timeline_signal(ev->context->ktimeline, ev->timestamp);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700118 kgsl_context_put(ev->context);
119 kfree(ev);
120}
121
122static int _add_fence_event(struct kgsl_device *device,
123 struct kgsl_context *context, unsigned int timestamp)
124{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530125 struct kgsl_sync_fence_event_priv *event;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700126 int ret;
127
128 event = kmalloc(sizeof(*event), GFP_KERNEL);
129 if (event == NULL)
130 return -ENOMEM;
131
132 /*
133 * Increase the refcount for the context to keep it through the
134 * callback
135 */
136 if (!_kgsl_context_get(context)) {
137 kfree(event);
138 return -ENOENT;
139 }
140
141 event->context = context;
142 event->timestamp = timestamp;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700143
144 ret = kgsl_add_event(device, &context->events, timestamp,
Lynus Vazc031a9b2017-01-25 13:00:13 +0530145 kgsl_sync_fence_event_cb, event);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700146
147 if (ret) {
148 kgsl_context_put(context);
149 kfree(event);
150 }
151
152 return ret;
153}
154
Lynus Vazc50d6202017-03-23 13:42:58 +0530155/* Only to be used if creating a related event failed */
156static void kgsl_sync_cancel(struct kgsl_sync_fence *kfence)
157{
158 spin_lock(&kfence->parent->lock);
159 if (!list_empty(&kfence->child_list)) {
160 list_del_init(&kfence->child_list);
161 fence_put(&kfence->fence);
162 }
163 spin_unlock(&kfence->parent->lock);
164}
165
Shrenuj Bansala419c792016-10-20 14:05:11 -0700166/**
167 * kgsl_add_fence_event - Create a new fence event
168 * @device - KGSL device to create the event on
169 * @timestamp - Timestamp to trigger the event
170 * @data - Return fence fd stored in struct kgsl_timestamp_event_fence
171 * @len - length of the fence event
172 * @owner - driver instance that owns this event
173 * @returns 0 on success or error code on error
174 *
175 * Create a fence and register an event to signal the fence when
176 * the timestamp expires
177 */
178
179int kgsl_add_fence_event(struct kgsl_device *device,
180 u32 context_id, u32 timestamp, void __user *data, int len,
181 struct kgsl_device_private *owner)
182{
183 struct kgsl_timestamp_event_fence priv;
184 struct kgsl_context *context;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530185 struct kgsl_sync_fence *kfence = NULL;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700186 int ret = -EINVAL;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700187 unsigned int cur;
188
189 priv.fence_fd = -1;
190
191 if (len != sizeof(priv))
192 return -EINVAL;
193
194 context = kgsl_context_get_owner(owner, context_id);
195
196 if (context == NULL)
197 return -EINVAL;
198
199 if (test_bit(KGSL_CONTEXT_PRIV_INVALID, &context->priv))
200 goto out;
201
Lynus Vazc031a9b2017-01-25 13:00:13 +0530202 kfence = kgsl_sync_fence_create(context, timestamp);
203 if (kfence == NULL) {
204 KGSL_DRV_CRIT_RATELIMIT(device,
205 "kgsl_sync_fence_create failed\n");
Shrenuj Bansala419c792016-10-20 14:05:11 -0700206 ret = -ENOMEM;
207 goto out;
208 }
209
210 priv.fence_fd = get_unused_fd_flags(0);
211 if (priv.fence_fd < 0) {
212 KGSL_DRV_CRIT_RATELIMIT(device,
213 "Unable to get a file descriptor: %d\n",
214 priv.fence_fd);
215 ret = priv.fence_fd;
216 goto out;
217 }
218
219 /*
220 * If the timestamp hasn't expired yet create an event to trigger it.
221 * Otherwise, just signal the fence - there is no reason to go through
222 * the effort of creating a fence we don't need.
223 */
224
225 kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED, &cur);
226
227 if (timestamp_cmp(cur, timestamp) >= 0) {
228 ret = 0;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530229 kgsl_sync_timeline_signal(context->ktimeline, cur);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700230 } else {
231 ret = _add_fence_event(device, context, timestamp);
232 if (ret)
233 goto out;
234 }
235
236 if (copy_to_user(data, &priv, sizeof(priv))) {
237 ret = -EFAULT;
238 goto out;
239 }
Lynus Vazc031a9b2017-01-25 13:00:13 +0530240 fd_install(priv.fence_fd, kfence->sync_file->file);
241
Shrenuj Bansala419c792016-10-20 14:05:11 -0700242out:
243 kgsl_context_put(context);
244 if (ret) {
245 if (priv.fence_fd >= 0)
246 put_unused_fd(priv.fence_fd);
247
Lynus Vazc031a9b2017-01-25 13:00:13 +0530248 if (kfence) {
Lynus Vazc50d6202017-03-23 13:42:58 +0530249 kgsl_sync_cancel(kfence);
Lynus Vazc031a9b2017-01-25 13:00:13 +0530250 /*
251 * Put the refcount of sync file. This will release
252 * kfence->fence as well.
253 */
254 fput(kfence->sync_file->file);
255 }
Shrenuj Bansala419c792016-10-20 14:05:11 -0700256 }
257 return ret;
258}
259
Lynus Vazc031a9b2017-01-25 13:00:13 +0530260static unsigned int kgsl_sync_fence_get_timestamp(
261 struct kgsl_sync_timeline *ktimeline,
262 enum kgsl_timestamp_type type)
Shrenuj Bansala419c792016-10-20 14:05:11 -0700263{
264 unsigned int ret = 0;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700265
266 if (ktimeline->device == NULL)
267 return 0;
268
Lynus Vazc031a9b2017-01-25 13:00:13 +0530269 kgsl_readtimestamp(ktimeline->device, ktimeline->context, type, &ret);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700270
Shrenuj Bansala419c792016-10-20 14:05:11 -0700271 return ret;
272}
273
Lynus Vazc031a9b2017-01-25 13:00:13 +0530274static void kgsl_sync_timeline_value_str(struct fence *fence,
275 char *str, int size)
Shrenuj Bansala419c792016-10-20 14:05:11 -0700276{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530277 struct kgsl_sync_fence *kfence = (struct kgsl_sync_fence *)fence;
278 struct kgsl_sync_timeline *ktimeline = kfence->parent;
279
280 unsigned int timestamp_retired;
281 unsigned int timestamp_queued;
282
283 if (!kref_get_unless_zero(&ktimeline->kref))
284 return;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700285
286 /*
287 * This callback can be called before the device and spinlock are
288 * initialized in struct kgsl_sync_timeline. kgsl_sync_get_timestamp()
289 * will check if device is NULL and return 0. Queued and retired
290 * timestamp of the context will be reported as 0, which is correct
291 * because the context and timeline are just getting initialized.
292 */
Lynus Vazc031a9b2017-01-25 13:00:13 +0530293 timestamp_retired = kgsl_sync_fence_get_timestamp(ktimeline,
294 KGSL_TIMESTAMP_RETIRED);
295 timestamp_queued = kgsl_sync_fence_get_timestamp(ktimeline,
296 KGSL_TIMESTAMP_QUEUED);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700297
298 snprintf(str, size, "%u queued:%u retired:%u",
299 ktimeline->last_timestamp,
300 timestamp_queued, timestamp_retired);
Lynus Vazc031a9b2017-01-25 13:00:13 +0530301
302 kgsl_sync_timeline_put(ktimeline);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700303}
304
Lynus Vazc031a9b2017-01-25 13:00:13 +0530305static void kgsl_sync_fence_value_str(struct fence *fence, char *str, int size)
Shrenuj Bansala419c792016-10-20 14:05:11 -0700306{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530307 struct kgsl_sync_fence *kfence = (struct kgsl_sync_fence *)fence;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700308
Lynus Vazc031a9b2017-01-25 13:00:13 +0530309 snprintf(str, size, "%u", kfence->timestamp);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700310}
311
Lynus Vazc031a9b2017-01-25 13:00:13 +0530312static const char *kgsl_sync_fence_driver_name(struct fence *fence)
Shrenuj Bansala419c792016-10-20 14:05:11 -0700313{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530314 return "kgsl-timeline";
Shrenuj Bansala419c792016-10-20 14:05:11 -0700315}
316
Lynus Vazc031a9b2017-01-25 13:00:13 +0530317static const char *kgsl_sync_timeline_name(struct fence *fence)
Shrenuj Bansala419c792016-10-20 14:05:11 -0700318{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530319 struct kgsl_sync_fence *kfence = (struct kgsl_sync_fence *)fence;
320 struct kgsl_sync_timeline *ktimeline = kfence->parent;
321
322 return ktimeline->name;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700323}
Shrenuj Bansala419c792016-10-20 14:05:11 -0700324
325int kgsl_sync_timeline_create(struct kgsl_context *context)
326{
327 struct kgsl_sync_timeline *ktimeline;
328
329 /*
330 * Generate a name which includes the thread name, thread id, process
331 * name, process id, and context id. This makes it possible to
332 * identify the context of a timeline in the sync dump.
333 */
Lynus Vazc031a9b2017-01-25 13:00:13 +0530334 char ktimeline_name[sizeof(ktimeline->name)] = {};
335
336 /* Put context when timeline is released */
337 if (!_kgsl_context_get(context))
338 return -ENOENT;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700339
340 snprintf(ktimeline_name, sizeof(ktimeline_name),
341 "%s_%.15s(%d)-%.15s(%d)-%d",
342 context->device->name,
343 current->group_leader->comm, current->group_leader->pid,
344 current->comm, current->pid, context->id);
345
Lynus Vazc031a9b2017-01-25 13:00:13 +0530346 ktimeline = kzalloc(sizeof(*ktimeline), GFP_KERNEL);
347 if (ktimeline == NULL) {
348 kgsl_context_put(context);
349 return -ENOMEM;
350 }
Shrenuj Bansala419c792016-10-20 14:05:11 -0700351
Lynus Vazc031a9b2017-01-25 13:00:13 +0530352 kref_init(&ktimeline->kref);
353 strlcpy(ktimeline->name, ktimeline_name, KGSL_TIMELINE_NAME_LEN);
354 ktimeline->fence_context = fence_context_alloc(1);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700355 ktimeline->last_timestamp = 0;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530356 INIT_LIST_HEAD(&ktimeline->child_list_head);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700357 spin_lock_init(&ktimeline->lock);
Lynus Vazc031a9b2017-01-25 13:00:13 +0530358 ktimeline->device = context->device;
359 ktimeline->context = context;
360
361 context->ktimeline = ktimeline;
362
Shrenuj Bansala419c792016-10-20 14:05:11 -0700363 return 0;
364}
365
Lynus Vazc031a9b2017-01-25 13:00:13 +0530366static void kgsl_sync_timeline_signal(struct kgsl_sync_timeline *ktimeline,
367 unsigned int timestamp)
Shrenuj Bansala419c792016-10-20 14:05:11 -0700368{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530369 unsigned long flags;
370 struct kgsl_sync_fence *kfence, *next;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700371
Lynus Vazc031a9b2017-01-25 13:00:13 +0530372 kref_get(&ktimeline->kref);
373
374 spin_lock_irqsave(&ktimeline->lock, flags);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700375 if (timestamp_cmp(timestamp, ktimeline->last_timestamp) > 0)
376 ktimeline->last_timestamp = timestamp;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700377
Lynus Vazc031a9b2017-01-25 13:00:13 +0530378 list_for_each_entry_safe(kfence, next, &ktimeline->child_list_head,
379 child_list) {
380 if (fence_is_signaled_locked(&kfence->fence)) {
Lynus Vazc50d6202017-03-23 13:42:58 +0530381 list_del_init(&kfence->child_list);
Lynus Vazc031a9b2017-01-25 13:00:13 +0530382 fence_put(&kfence->fence);
383 }
384 }
385
386 spin_unlock_irqrestore(&ktimeline->lock, flags);
387 kgsl_sync_timeline_put(ktimeline);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700388}
389
390void kgsl_sync_timeline_destroy(struct kgsl_context *context)
391{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530392 kfree(context->ktimeline);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700393}
394
Lynus Vazc031a9b2017-01-25 13:00:13 +0530395static void kgsl_sync_timeline_release(struct kref *kref)
Shrenuj Bansala419c792016-10-20 14:05:11 -0700396{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530397 struct kgsl_sync_timeline *ktimeline =
398 container_of(kref, struct kgsl_sync_timeline, kref);
399
400 /*
401 * Only put the context refcount here. The context destroy function
402 * will call kgsl_sync_timeline_destroy() to kfree it
403 */
404 kgsl_context_put(ktimeline->context);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700405}
406
Lynus Vazc031a9b2017-01-25 13:00:13 +0530407void kgsl_sync_timeline_put(struct kgsl_sync_timeline *ktimeline)
408{
409 if (ktimeline)
410 kref_put(&ktimeline->kref, kgsl_sync_timeline_release);
411}
412
413static const struct fence_ops kgsl_sync_fence_ops = {
414 .get_driver_name = kgsl_sync_fence_driver_name,
415 .get_timeline_name = kgsl_sync_timeline_name,
416 .enable_signaling = kgsl_enable_signaling,
417 .signaled = kgsl_sync_fence_has_signaled,
418 .wait = fence_default_wait,
419 .release = kgsl_sync_fence_release,
420
421 .fence_value_str = kgsl_sync_fence_value_str,
422 .timeline_value_str = kgsl_sync_timeline_value_str,
423};
424
425static void kgsl_sync_fence_callback(struct fence *fence, struct fence_cb *cb)
426{
427 struct kgsl_sync_fence_cb *kcb = (struct kgsl_sync_fence_cb *)cb;
428
429 kcb->func(kcb->priv);
430 fence_put(kcb->fence);
431 kfree(kcb);
432}
433
Lynus Vaze99b92b2017-04-24 18:04:54 +0530434static void kgsl_get_fence_name(struct fence *fence,
435 char *fence_name, int name_len)
436{
437 char *ptr = fence_name;
438 char *last = fence_name + name_len;
439
440 ptr += snprintf(ptr, last - ptr, "%s %s",
441 fence->ops->get_driver_name(fence),
442 fence->ops->get_timeline_name(fence));
443
444 if ((ptr + 2) >= last)
445 return;
446
447 if (fence->ops->fence_value_str) {
448 ptr += snprintf(ptr, last - ptr, ": ");
449 fence->ops->fence_value_str(fence, ptr, last - ptr);
450 }
451}
452
Lynus Vazc031a9b2017-01-25 13:00:13 +0530453struct kgsl_sync_fence_cb *kgsl_sync_fence_async_wait(int fd,
Lynus Vaze99b92b2017-04-24 18:04:54 +0530454 void (*func)(void *priv), void *priv, char *fence_name, int name_len)
Shrenuj Bansala419c792016-10-20 14:05:11 -0700455{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530456 struct kgsl_sync_fence_cb *kcb;
457 struct fence *fence;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700458 int status;
459
Lynus Vazc031a9b2017-01-25 13:00:13 +0530460 fence = sync_file_get_fence(fd);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700461 if (fence == NULL)
462 return ERR_PTR(-EINVAL);
463
Lynus Vazc031a9b2017-01-25 13:00:13 +0530464 /* create the callback */
465 kcb = kzalloc(sizeof(*kcb), GFP_ATOMIC);
466 if (kcb == NULL) {
467 fence_put(fence);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700468 return ERR_PTR(-ENOMEM);
469 }
470
Lynus Vazc031a9b2017-01-25 13:00:13 +0530471 kcb->fence = fence;
472 kcb->priv = priv;
473 kcb->func = func;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700474
Lynus Vaze99b92b2017-04-24 18:04:54 +0530475 if (fence_name)
476 kgsl_get_fence_name(fence, fence_name, name_len);
477
Shrenuj Bansala419c792016-10-20 14:05:11 -0700478 /* if status then error or signaled */
Lynus Vazc031a9b2017-01-25 13:00:13 +0530479 status = fence_add_callback(fence, &kcb->fence_cb,
480 kgsl_sync_fence_callback);
481
Shrenuj Bansala419c792016-10-20 14:05:11 -0700482 if (status) {
Lynus Vazc031a9b2017-01-25 13:00:13 +0530483 kfree(kcb);
Harshdeep Dhatt0ed60a42017-04-20 16:41:50 -0600484 if (!fence_is_signaled(fence))
Lynus Vazc031a9b2017-01-25 13:00:13 +0530485 kcb = ERR_PTR(status);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700486 else
Lynus Vazc031a9b2017-01-25 13:00:13 +0530487 kcb = NULL;
488 fence_put(fence);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700489 }
490
Lynus Vazc031a9b2017-01-25 13:00:13 +0530491 return kcb;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700492}
493
Lynus Vazc031a9b2017-01-25 13:00:13 +0530494int kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_cb *kcb)
Shrenuj Bansala419c792016-10-20 14:05:11 -0700495{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530496 if (kcb == NULL)
Shrenuj Bansala419c792016-10-20 14:05:11 -0700497 return 0;
498
Lynus Vazc031a9b2017-01-25 13:00:13 +0530499 if (fence_remove_callback(kcb->fence, &kcb->fence_cb)) {
500 fence_put(kcb->fence);
501 kfree(kcb);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700502 return 1;
503 }
504 return 0;
505}
506
Shrenuj Bansala419c792016-10-20 14:05:11 -0700507struct kgsl_syncsource {
508 struct kref refcount;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530509 char name[KGSL_TIMELINE_NAME_LEN];
Shrenuj Bansala419c792016-10-20 14:05:11 -0700510 int id;
511 struct kgsl_process_private *private;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530512 struct list_head child_list_head;
513 spinlock_t lock;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700514};
515
Lynus Vazc031a9b2017-01-25 13:00:13 +0530516struct kgsl_syncsource_fence {
517 struct fence fence;
518 struct kgsl_syncsource *parent;
519 struct list_head child_list;
520};
521
522static const struct fence_ops kgsl_syncsource_fence_ops;
523
Shrenuj Bansala419c792016-10-20 14:05:11 -0700524long kgsl_ioctl_syncsource_create(struct kgsl_device_private *dev_priv,
525 unsigned int cmd, void *data)
526{
527 struct kgsl_syncsource *syncsource = NULL;
528 struct kgsl_syncsource_create *param = data;
529 int ret = -EINVAL;
530 int id = 0;
531 struct kgsl_process_private *private = dev_priv->process_priv;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530532 char name[KGSL_TIMELINE_NAME_LEN];
533
534 if (!kgsl_process_private_get(private))
535 return ret;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700536
537 syncsource = kzalloc(sizeof(*syncsource), GFP_KERNEL);
538 if (syncsource == NULL) {
539 ret = -ENOMEM;
540 goto out;
541 }
542
543 snprintf(name, sizeof(name), "kgsl-syncsource-pid-%d",
544 current->group_leader->pid);
545
Shrenuj Bansala419c792016-10-20 14:05:11 -0700546 kref_init(&syncsource->refcount);
Lynus Vazc031a9b2017-01-25 13:00:13 +0530547 strlcpy(syncsource->name, name, KGSL_TIMELINE_NAME_LEN);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700548 syncsource->private = private;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530549 INIT_LIST_HEAD(&syncsource->child_list_head);
550 spin_lock_init(&syncsource->lock);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700551
552 idr_preload(GFP_KERNEL);
553 spin_lock(&private->syncsource_lock);
554 id = idr_alloc(&private->syncsource_idr, syncsource, 1, 0, GFP_NOWAIT);
555 if (id > 0) {
556 syncsource->id = id;
557 param->id = id;
558 ret = 0;
559 } else {
560 ret = id;
561 }
562
563 spin_unlock(&private->syncsource_lock);
564 idr_preload_end();
565
566out:
567 if (ret) {
Lynus Vazc031a9b2017-01-25 13:00:13 +0530568 kgsl_process_private_put(private);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700569 kfree(syncsource);
570 }
571
572 return ret;
573}
574
575static struct kgsl_syncsource *
576kgsl_syncsource_get(struct kgsl_process_private *private, int id)
577{
578 int result = 0;
579 struct kgsl_syncsource *syncsource = NULL;
580
581 spin_lock(&private->syncsource_lock);
582
583 syncsource = idr_find(&private->syncsource_idr, id);
584 if (syncsource)
585 result = kref_get_unless_zero(&syncsource->refcount);
586
587 spin_unlock(&private->syncsource_lock);
588
589 return result ? syncsource : NULL;
590}
591
592static void kgsl_syncsource_destroy(struct kref *kref)
593{
594 struct kgsl_syncsource *syncsource = container_of(kref,
595 struct kgsl_syncsource,
596 refcount);
597
598 struct kgsl_process_private *private = syncsource->private;
599
Lynus Vazc031a9b2017-01-25 13:00:13 +0530600 /* Done with process private. Release the refcount */
601 kgsl_process_private_put(private);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700602
603 kfree(syncsource);
604}
605
606void kgsl_syncsource_put(struct kgsl_syncsource *syncsource)
607{
608 if (syncsource)
609 kref_put(&syncsource->refcount, kgsl_syncsource_destroy);
610}
611
Lynus Vazc031a9b2017-01-25 13:00:13 +0530612void kgsl_syncsource_cleanup(struct kgsl_process_private *private,
613 struct kgsl_syncsource *syncsource)
614{
615 struct kgsl_syncsource_fence *sfence, *next;
616
617 spin_lock(&private->syncsource_lock);
618 if (syncsource->id != 0) {
619 idr_remove(&private->syncsource_idr, syncsource->id);
620 syncsource->id = 0;
621 }
622 spin_unlock(&private->syncsource_lock);
623
624 /* Signal all fences to release any callbacks */
625 spin_lock(&syncsource->lock);
626
627 list_for_each_entry_safe(sfence, next, &syncsource->child_list_head,
628 child_list) {
629 fence_signal_locked(&sfence->fence);
630 list_del_init(&sfence->child_list);
631 }
632
633 spin_unlock(&syncsource->lock);
634
635 /* put reference from syncsource creation */
636 kgsl_syncsource_put(syncsource);
637}
638
Shrenuj Bansala419c792016-10-20 14:05:11 -0700639long kgsl_ioctl_syncsource_destroy(struct kgsl_device_private *dev_priv,
640 unsigned int cmd, void *data)
641{
642 struct kgsl_syncsource_destroy *param = data;
643 struct kgsl_syncsource *syncsource = NULL;
644 struct kgsl_process_private *private = dev_priv->process_priv;
645
646 spin_lock(&private->syncsource_lock);
647 syncsource = idr_find(&private->syncsource_idr, param->id);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700648 spin_unlock(&private->syncsource_lock);
649
650 if (syncsource == NULL)
651 return -EINVAL;
652
Lynus Vazc031a9b2017-01-25 13:00:13 +0530653 kgsl_syncsource_cleanup(private, syncsource);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700654 return 0;
655}
656
657long kgsl_ioctl_syncsource_create_fence(struct kgsl_device_private *dev_priv,
658 unsigned int cmd, void *data)
659{
660 struct kgsl_syncsource_create_fence *param = data;
661 struct kgsl_syncsource *syncsource = NULL;
662 int ret = -EINVAL;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530663 struct kgsl_syncsource_fence *sfence = NULL;
664 struct sync_file *sync_file = NULL;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700665 int fd = -1;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700666
Lynus Vazc031a9b2017-01-25 13:00:13 +0530667 /*
668 * Take a refcount that is released when the fence is released
669 * (or if fence can't be added to the syncsource).
670 */
Shrenuj Bansala419c792016-10-20 14:05:11 -0700671 syncsource = kgsl_syncsource_get(dev_priv->process_priv,
672 param->id);
673 if (syncsource == NULL)
674 goto out;
675
Lynus Vazc031a9b2017-01-25 13:00:13 +0530676 sfence = kzalloc(sizeof(*sfence), GFP_KERNEL);
677 if (sfence == NULL) {
678 ret = -ENOMEM;
679 goto out;
680 }
681 sfence->parent = syncsource;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700682
Lynus Vazc031a9b2017-01-25 13:00:13 +0530683 /* Use a new fence context for each fence */
684 fence_init(&sfence->fence, &kgsl_syncsource_fence_ops,
685 &syncsource->lock, fence_context_alloc(1), 1);
686
687 sync_file = sync_file_create(&sfence->fence);
688
689 if (sync_file == NULL) {
690 KGSL_DRV_ERR(dev_priv->device, "Create sync_file failed\n");
Shrenuj Bansala419c792016-10-20 14:05:11 -0700691 ret = -ENOMEM;
692 goto out;
693 }
694
695 fd = get_unused_fd_flags(0);
696 if (fd < 0) {
697 ret = -EBADF;
698 goto out;
699 }
700 ret = 0;
701
Lynus Vazc031a9b2017-01-25 13:00:13 +0530702 fd_install(fd, sync_file->file);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700703
704 param->fence_fd = fd;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530705
706 spin_lock(&syncsource->lock);
707 list_add_tail(&sfence->child_list, &syncsource->child_list_head);
708 spin_unlock(&syncsource->lock);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700709out:
710 if (ret) {
Lynus Vazc031a9b2017-01-25 13:00:13 +0530711 if (sync_file)
712 fput(sync_file->file);
713 else if (sfence)
714 fence_put(&sfence->fence);
715 kgsl_syncsource_put(syncsource);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700716 }
Lynus Vazc031a9b2017-01-25 13:00:13 +0530717
718 return ret;
719}
720
721static int kgsl_syncsource_signal(struct kgsl_syncsource *syncsource,
722 struct fence *fence)
723{
724 struct kgsl_syncsource_fence *sfence, *next;
725 int ret = -EINVAL;
726
727 spin_lock(&syncsource->lock);
728
729 list_for_each_entry_safe(sfence, next, &syncsource->child_list_head,
730 child_list) {
731 if (fence == &sfence->fence) {
732 fence_signal_locked(fence);
733 list_del_init(&sfence->child_list);
734
735 ret = 0;
736 break;
737 }
738 }
739
740 spin_unlock(&syncsource->lock);
741
Shrenuj Bansala419c792016-10-20 14:05:11 -0700742 return ret;
743}
744
745long kgsl_ioctl_syncsource_signal_fence(struct kgsl_device_private *dev_priv,
746 unsigned int cmd, void *data)
747{
748 int ret = -EINVAL;
749 struct kgsl_syncsource_signal_fence *param = data;
750 struct kgsl_syncsource *syncsource = NULL;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530751 struct fence *fence = NULL;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700752
753 syncsource = kgsl_syncsource_get(dev_priv->process_priv,
754 param->id);
755 if (syncsource == NULL)
756 goto out;
757
Lynus Vazc031a9b2017-01-25 13:00:13 +0530758 fence = sync_file_get_fence(param->fence_fd);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700759 if (fence == NULL) {
760 ret = -EBADF;
761 goto out;
762 }
763
Lynus Vazc031a9b2017-01-25 13:00:13 +0530764 ret = kgsl_syncsource_signal(syncsource, fence);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700765out:
766 if (fence)
Lynus Vazc031a9b2017-01-25 13:00:13 +0530767 fence_put(fence);
768 if (syncsource)
769 kgsl_syncsource_put(syncsource);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700770 return ret;
771}
Lynus Vazc031a9b2017-01-25 13:00:13 +0530772
773static void kgsl_syncsource_fence_release(struct fence *fence)
774{
775 struct kgsl_syncsource_fence *sfence =
776 (struct kgsl_syncsource_fence *)fence;
777
778 /* Signal if it's not signaled yet */
779 kgsl_syncsource_signal(sfence->parent, fence);
780
781 /* Release the refcount on the syncsource */
782 kgsl_syncsource_put(sfence->parent);
783
784 kfree(sfence);
785}
786
787static const char *kgsl_syncsource_get_timeline_name(struct fence *fence)
788{
789 struct kgsl_syncsource_fence *sfence =
790 (struct kgsl_syncsource_fence *)fence;
791 struct kgsl_syncsource *syncsource = sfence->parent;
792
793 return syncsource->name;
794}
795
796static bool kgsl_syncsource_enable_signaling(struct fence *fence)
797{
798 return true;
799}
800
801static const char *kgsl_syncsource_driver_name(struct fence *fence)
802{
803 return "kgsl-syncsource-timeline";
804}
805
806static const struct fence_ops kgsl_syncsource_fence_ops = {
807 .get_driver_name = kgsl_syncsource_driver_name,
808 .get_timeline_name = kgsl_syncsource_get_timeline_name,
809 .enable_signaling = kgsl_syncsource_enable_signaling,
810 .wait = fence_default_wait,
811 .release = kgsl_syncsource_fence_release,
812};
813