blob: 817a6b10ec9c7bdad0157cca755ee1c1081f5870 [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
Lynus Vaz9d6334b2017-06-27 14:57:56 +053055 /*
56 * sync_file_create() takes a refcount to the fence. This refcount is
57 * put when the fence is signaled.
58 */
Lynus Vazc031a9b2017-01-25 13:00:13 +053059 kfence->sync_file = sync_file_create(&kfence->fence);
60
61 if (kfence->sync_file == NULL) {
62 kgsl_sync_timeline_put(ktimeline);
63 KGSL_DRV_ERR(context->device, "Create sync_file failed\n");
64 kfree(kfence);
65 return NULL;
66 }
67
Lynus Vazc031a9b2017-01-25 13:00:13 +053068 spin_lock_irqsave(&ktimeline->lock, flags);
69 list_add_tail(&kfence->child_list, &ktimeline->child_list_head);
70 spin_unlock_irqrestore(&ktimeline->lock, flags);
71
72 return kfence;
Shrenuj Bansala419c792016-10-20 14:05:11 -070073}
74
Lynus Vazc031a9b2017-01-25 13:00:13 +053075static void kgsl_sync_fence_release(struct fence *fence)
Shrenuj Bansala419c792016-10-20 14:05:11 -070076{
Lynus Vazc031a9b2017-01-25 13:00:13 +053077 struct kgsl_sync_fence *kfence = (struct kgsl_sync_fence *)fence;
78
79 kgsl_sync_timeline_put(kfence->parent);
80 kfree(kfence);
Shrenuj Bansala419c792016-10-20 14:05:11 -070081}
82
Lynus Vazc031a9b2017-01-25 13:00:13 +053083/* Called with ktimeline->lock held */
84bool kgsl_sync_fence_has_signaled(struct fence *fence)
Shrenuj Bansala419c792016-10-20 14:05:11 -070085{
Lynus Vazc031a9b2017-01-25 13:00:13 +053086 struct kgsl_sync_fence *kfence = (struct kgsl_sync_fence *)fence;
87 struct kgsl_sync_timeline *ktimeline = kfence->parent;
88 unsigned int ts = kfence->timestamp;
Shrenuj Bansala419c792016-10-20 14:05:11 -070089
Lynus Vazc031a9b2017-01-25 13:00:13 +053090 return (timestamp_cmp(ktimeline->last_timestamp, ts) >= 0);
Shrenuj Bansala419c792016-10-20 14:05:11 -070091}
92
Lynus Vazc031a9b2017-01-25 13:00:13 +053093bool kgsl_enable_signaling(struct fence *fence)
Shrenuj Bansala419c792016-10-20 14:05:11 -070094{
Lynus Vazc031a9b2017-01-25 13:00:13 +053095 return !kgsl_sync_fence_has_signaled(fence);
Shrenuj Bansala419c792016-10-20 14:05:11 -070096}
97
Lynus Vazc031a9b2017-01-25 13:00:13 +053098struct kgsl_sync_fence_event_priv {
Shrenuj Bansala419c792016-10-20 14:05:11 -070099 struct kgsl_context *context;
100 unsigned int timestamp;
101};
102
103/**
Lynus Vazc031a9b2017-01-25 13:00:13 +0530104 * kgsl_sync_fence_event_cb - Event callback for a fence timestamp event
Shrenuj Bansala419c792016-10-20 14:05:11 -0700105 * @device - The KGSL device that expired the timestamp
106 * @context- Pointer to the context that owns the event
107 * @priv: Private data for the callback
108 * @result - Result of the event (retired or canceled)
109 *
110 * Signal a fence following the expiration of a timestamp
111 */
112
Lynus Vazc031a9b2017-01-25 13:00:13 +0530113static void kgsl_sync_fence_event_cb(struct kgsl_device *device,
Shrenuj Bansala419c792016-10-20 14:05:11 -0700114 struct kgsl_event_group *group, void *priv, int result)
115{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530116 struct kgsl_sync_fence_event_priv *ev = priv;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700117
Lynus Vazc031a9b2017-01-25 13:00:13 +0530118 kgsl_sync_timeline_signal(ev->context->ktimeline, ev->timestamp);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700119 kgsl_context_put(ev->context);
120 kfree(ev);
121}
122
123static int _add_fence_event(struct kgsl_device *device,
124 struct kgsl_context *context, unsigned int timestamp)
125{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530126 struct kgsl_sync_fence_event_priv *event;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700127 int ret;
128
129 event = kmalloc(sizeof(*event), GFP_KERNEL);
130 if (event == NULL)
131 return -ENOMEM;
132
133 /*
134 * Increase the refcount for the context to keep it through the
135 * callback
136 */
137 if (!_kgsl_context_get(context)) {
138 kfree(event);
139 return -ENOENT;
140 }
141
142 event->context = context;
143 event->timestamp = timestamp;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700144
145 ret = kgsl_add_event(device, &context->events, timestamp,
Lynus Vazc031a9b2017-01-25 13:00:13 +0530146 kgsl_sync_fence_event_cb, event);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700147
148 if (ret) {
149 kgsl_context_put(context);
150 kfree(event);
151 }
152
153 return ret;
154}
155
Lynus Vazc50d6202017-03-23 13:42:58 +0530156/* Only to be used if creating a related event failed */
157static void kgsl_sync_cancel(struct kgsl_sync_fence *kfence)
158{
159 spin_lock(&kfence->parent->lock);
160 if (!list_empty(&kfence->child_list)) {
161 list_del_init(&kfence->child_list);
162 fence_put(&kfence->fence);
163 }
164 spin_unlock(&kfence->parent->lock);
165}
166
Shrenuj Bansala419c792016-10-20 14:05:11 -0700167/**
168 * kgsl_add_fence_event - Create a new fence event
169 * @device - KGSL device to create the event on
170 * @timestamp - Timestamp to trigger the event
171 * @data - Return fence fd stored in struct kgsl_timestamp_event_fence
172 * @len - length of the fence event
173 * @owner - driver instance that owns this event
174 * @returns 0 on success or error code on error
175 *
176 * Create a fence and register an event to signal the fence when
177 * the timestamp expires
178 */
179
180int kgsl_add_fence_event(struct kgsl_device *device,
181 u32 context_id, u32 timestamp, void __user *data, int len,
182 struct kgsl_device_private *owner)
183{
184 struct kgsl_timestamp_event_fence priv;
185 struct kgsl_context *context;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530186 struct kgsl_sync_fence *kfence = NULL;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700187 int ret = -EINVAL;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700188 unsigned int cur;
189
190 priv.fence_fd = -1;
191
192 if (len != sizeof(priv))
193 return -EINVAL;
194
195 context = kgsl_context_get_owner(owner, context_id);
196
197 if (context == NULL)
198 return -EINVAL;
199
200 if (test_bit(KGSL_CONTEXT_PRIV_INVALID, &context->priv))
201 goto out;
202
Lynus Vazc031a9b2017-01-25 13:00:13 +0530203 kfence = kgsl_sync_fence_create(context, timestamp);
204 if (kfence == NULL) {
205 KGSL_DRV_CRIT_RATELIMIT(device,
206 "kgsl_sync_fence_create failed\n");
Shrenuj Bansala419c792016-10-20 14:05:11 -0700207 ret = -ENOMEM;
208 goto out;
209 }
210
211 priv.fence_fd = get_unused_fd_flags(0);
212 if (priv.fence_fd < 0) {
213 KGSL_DRV_CRIT_RATELIMIT(device,
214 "Unable to get a file descriptor: %d\n",
215 priv.fence_fd);
216 ret = priv.fence_fd;
217 goto out;
218 }
219
220 /*
221 * If the timestamp hasn't expired yet create an event to trigger it.
222 * Otherwise, just signal the fence - there is no reason to go through
223 * the effort of creating a fence we don't need.
224 */
225
226 kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED, &cur);
227
228 if (timestamp_cmp(cur, timestamp) >= 0) {
229 ret = 0;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530230 kgsl_sync_timeline_signal(context->ktimeline, cur);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700231 } else {
232 ret = _add_fence_event(device, context, timestamp);
233 if (ret)
234 goto out;
235 }
236
237 if (copy_to_user(data, &priv, sizeof(priv))) {
238 ret = -EFAULT;
239 goto out;
240 }
Lynus Vazc031a9b2017-01-25 13:00:13 +0530241 fd_install(priv.fence_fd, kfence->sync_file->file);
242
Shrenuj Bansala419c792016-10-20 14:05:11 -0700243out:
244 kgsl_context_put(context);
245 if (ret) {
246 if (priv.fence_fd >= 0)
247 put_unused_fd(priv.fence_fd);
248
Lynus Vazc031a9b2017-01-25 13:00:13 +0530249 if (kfence) {
Lynus Vazc50d6202017-03-23 13:42:58 +0530250 kgsl_sync_cancel(kfence);
Lynus Vazc031a9b2017-01-25 13:00:13 +0530251 /*
252 * Put the refcount of sync file. This will release
253 * kfence->fence as well.
254 */
255 fput(kfence->sync_file->file);
256 }
Shrenuj Bansala419c792016-10-20 14:05:11 -0700257 }
258 return ret;
259}
260
Lynus Vazc031a9b2017-01-25 13:00:13 +0530261static unsigned int kgsl_sync_fence_get_timestamp(
262 struct kgsl_sync_timeline *ktimeline,
263 enum kgsl_timestamp_type type)
Shrenuj Bansala419c792016-10-20 14:05:11 -0700264{
265 unsigned int ret = 0;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700266
267 if (ktimeline->device == NULL)
268 return 0;
269
Lynus Vazc031a9b2017-01-25 13:00:13 +0530270 kgsl_readtimestamp(ktimeline->device, ktimeline->context, type, &ret);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700271
Shrenuj Bansala419c792016-10-20 14:05:11 -0700272 return ret;
273}
274
Lynus Vazc031a9b2017-01-25 13:00:13 +0530275static void kgsl_sync_timeline_value_str(struct fence *fence,
276 char *str, int size)
Shrenuj Bansala419c792016-10-20 14:05:11 -0700277{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530278 struct kgsl_sync_fence *kfence = (struct kgsl_sync_fence *)fence;
279 struct kgsl_sync_timeline *ktimeline = kfence->parent;
280
281 unsigned int timestamp_retired;
282 unsigned int timestamp_queued;
283
284 if (!kref_get_unless_zero(&ktimeline->kref))
285 return;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700286
287 /*
288 * This callback can be called before the device and spinlock are
289 * initialized in struct kgsl_sync_timeline. kgsl_sync_get_timestamp()
290 * will check if device is NULL and return 0. Queued and retired
291 * timestamp of the context will be reported as 0, which is correct
292 * because the context and timeline are just getting initialized.
293 */
Lynus Vazc031a9b2017-01-25 13:00:13 +0530294 timestamp_retired = kgsl_sync_fence_get_timestamp(ktimeline,
295 KGSL_TIMESTAMP_RETIRED);
296 timestamp_queued = kgsl_sync_fence_get_timestamp(ktimeline,
297 KGSL_TIMESTAMP_QUEUED);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700298
299 snprintf(str, size, "%u queued:%u retired:%u",
300 ktimeline->last_timestamp,
301 timestamp_queued, timestamp_retired);
Lynus Vazc031a9b2017-01-25 13:00:13 +0530302
303 kgsl_sync_timeline_put(ktimeline);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700304}
305
Lynus Vazc031a9b2017-01-25 13:00:13 +0530306static void kgsl_sync_fence_value_str(struct fence *fence, char *str, int size)
Shrenuj Bansala419c792016-10-20 14:05:11 -0700307{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530308 struct kgsl_sync_fence *kfence = (struct kgsl_sync_fence *)fence;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700309
Lynus Vazc031a9b2017-01-25 13:00:13 +0530310 snprintf(str, size, "%u", kfence->timestamp);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700311}
312
Lynus Vazc031a9b2017-01-25 13:00:13 +0530313static const char *kgsl_sync_fence_driver_name(struct fence *fence)
Shrenuj Bansala419c792016-10-20 14:05:11 -0700314{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530315 return "kgsl-timeline";
Shrenuj Bansala419c792016-10-20 14:05:11 -0700316}
317
Lynus Vazc031a9b2017-01-25 13:00:13 +0530318static const char *kgsl_sync_timeline_name(struct fence *fence)
Shrenuj Bansala419c792016-10-20 14:05:11 -0700319{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530320 struct kgsl_sync_fence *kfence = (struct kgsl_sync_fence *)fence;
321 struct kgsl_sync_timeline *ktimeline = kfence->parent;
322
323 return ktimeline->name;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700324}
Shrenuj Bansala419c792016-10-20 14:05:11 -0700325
326int kgsl_sync_timeline_create(struct kgsl_context *context)
327{
328 struct kgsl_sync_timeline *ktimeline;
329
330 /*
331 * Generate a name which includes the thread name, thread id, process
332 * name, process id, and context id. This makes it possible to
333 * identify the context of a timeline in the sync dump.
334 */
Lynus Vazc031a9b2017-01-25 13:00:13 +0530335 char ktimeline_name[sizeof(ktimeline->name)] = {};
336
337 /* Put context when timeline is released */
338 if (!_kgsl_context_get(context))
339 return -ENOENT;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700340
341 snprintf(ktimeline_name, sizeof(ktimeline_name),
342 "%s_%.15s(%d)-%.15s(%d)-%d",
343 context->device->name,
344 current->group_leader->comm, current->group_leader->pid,
345 current->comm, current->pid, context->id);
346
Lynus Vazc031a9b2017-01-25 13:00:13 +0530347 ktimeline = kzalloc(sizeof(*ktimeline), GFP_KERNEL);
348 if (ktimeline == NULL) {
349 kgsl_context_put(context);
350 return -ENOMEM;
351 }
Shrenuj Bansala419c792016-10-20 14:05:11 -0700352
Lynus Vazc031a9b2017-01-25 13:00:13 +0530353 kref_init(&ktimeline->kref);
354 strlcpy(ktimeline->name, ktimeline_name, KGSL_TIMELINE_NAME_LEN);
355 ktimeline->fence_context = fence_context_alloc(1);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700356 ktimeline->last_timestamp = 0;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530357 INIT_LIST_HEAD(&ktimeline->child_list_head);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700358 spin_lock_init(&ktimeline->lock);
Lynus Vazc031a9b2017-01-25 13:00:13 +0530359 ktimeline->device = context->device;
360 ktimeline->context = context;
361
362 context->ktimeline = ktimeline;
363
Shrenuj Bansala419c792016-10-20 14:05:11 -0700364 return 0;
365}
366
Lynus Vazc031a9b2017-01-25 13:00:13 +0530367static void kgsl_sync_timeline_signal(struct kgsl_sync_timeline *ktimeline,
368 unsigned int timestamp)
Shrenuj Bansala419c792016-10-20 14:05:11 -0700369{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530370 unsigned long flags;
371 struct kgsl_sync_fence *kfence, *next;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700372
Lynus Vazc031a9b2017-01-25 13:00:13 +0530373 kref_get(&ktimeline->kref);
374
375 spin_lock_irqsave(&ktimeline->lock, flags);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700376 if (timestamp_cmp(timestamp, ktimeline->last_timestamp) > 0)
377 ktimeline->last_timestamp = timestamp;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700378
Lynus Vazc031a9b2017-01-25 13:00:13 +0530379 list_for_each_entry_safe(kfence, next, &ktimeline->child_list_head,
380 child_list) {
381 if (fence_is_signaled_locked(&kfence->fence)) {
Lynus Vazc50d6202017-03-23 13:42:58 +0530382 list_del_init(&kfence->child_list);
Lynus Vazc031a9b2017-01-25 13:00:13 +0530383 fence_put(&kfence->fence);
384 }
385 }
386
387 spin_unlock_irqrestore(&ktimeline->lock, flags);
388 kgsl_sync_timeline_put(ktimeline);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700389}
390
391void kgsl_sync_timeline_destroy(struct kgsl_context *context)
392{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530393 kfree(context->ktimeline);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700394}
395
Lynus Vazc031a9b2017-01-25 13:00:13 +0530396static void kgsl_sync_timeline_release(struct kref *kref)
Shrenuj Bansala419c792016-10-20 14:05:11 -0700397{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530398 struct kgsl_sync_timeline *ktimeline =
399 container_of(kref, struct kgsl_sync_timeline, kref);
400
401 /*
402 * Only put the context refcount here. The context destroy function
403 * will call kgsl_sync_timeline_destroy() to kfree it
404 */
405 kgsl_context_put(ktimeline->context);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700406}
407
Lynus Vazc031a9b2017-01-25 13:00:13 +0530408void kgsl_sync_timeline_put(struct kgsl_sync_timeline *ktimeline)
409{
410 if (ktimeline)
411 kref_put(&ktimeline->kref, kgsl_sync_timeline_release);
412}
413
414static const struct fence_ops kgsl_sync_fence_ops = {
415 .get_driver_name = kgsl_sync_fence_driver_name,
416 .get_timeline_name = kgsl_sync_timeline_name,
417 .enable_signaling = kgsl_enable_signaling,
418 .signaled = kgsl_sync_fence_has_signaled,
419 .wait = fence_default_wait,
420 .release = kgsl_sync_fence_release,
421
422 .fence_value_str = kgsl_sync_fence_value_str,
423 .timeline_value_str = kgsl_sync_timeline_value_str,
424};
425
426static void kgsl_sync_fence_callback(struct fence *fence, struct fence_cb *cb)
427{
428 struct kgsl_sync_fence_cb *kcb = (struct kgsl_sync_fence_cb *)cb;
429
430 kcb->func(kcb->priv);
431 fence_put(kcb->fence);
432 kfree(kcb);
433}
434
Lynus Vaze99b92b2017-04-24 18:04:54 +0530435static void kgsl_get_fence_name(struct fence *fence,
436 char *fence_name, int name_len)
437{
438 char *ptr = fence_name;
439 char *last = fence_name + name_len;
440
441 ptr += snprintf(ptr, last - ptr, "%s %s",
442 fence->ops->get_driver_name(fence),
443 fence->ops->get_timeline_name(fence));
444
445 if ((ptr + 2) >= last)
446 return;
447
448 if (fence->ops->fence_value_str) {
449 ptr += snprintf(ptr, last - ptr, ": ");
450 fence->ops->fence_value_str(fence, ptr, last - ptr);
451 }
452}
453
Lynus Vazc031a9b2017-01-25 13:00:13 +0530454struct kgsl_sync_fence_cb *kgsl_sync_fence_async_wait(int fd,
Lynus Vaze99b92b2017-04-24 18:04:54 +0530455 void (*func)(void *priv), void *priv, char *fence_name, int name_len)
Shrenuj Bansala419c792016-10-20 14:05:11 -0700456{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530457 struct kgsl_sync_fence_cb *kcb;
458 struct fence *fence;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700459 int status;
460
Lynus Vazc031a9b2017-01-25 13:00:13 +0530461 fence = sync_file_get_fence(fd);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700462 if (fence == NULL)
463 return ERR_PTR(-EINVAL);
464
Lynus Vazc031a9b2017-01-25 13:00:13 +0530465 /* create the callback */
466 kcb = kzalloc(sizeof(*kcb), GFP_ATOMIC);
467 if (kcb == NULL) {
468 fence_put(fence);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700469 return ERR_PTR(-ENOMEM);
470 }
471
Lynus Vazc031a9b2017-01-25 13:00:13 +0530472 kcb->fence = fence;
473 kcb->priv = priv;
474 kcb->func = func;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700475
Lynus Vaze99b92b2017-04-24 18:04:54 +0530476 if (fence_name)
477 kgsl_get_fence_name(fence, fence_name, name_len);
478
Shrenuj Bansala419c792016-10-20 14:05:11 -0700479 /* if status then error or signaled */
Lynus Vazc031a9b2017-01-25 13:00:13 +0530480 status = fence_add_callback(fence, &kcb->fence_cb,
481 kgsl_sync_fence_callback);
482
Shrenuj Bansala419c792016-10-20 14:05:11 -0700483 if (status) {
Lynus Vazc031a9b2017-01-25 13:00:13 +0530484 kfree(kcb);
Harshdeep Dhatt0ed60a42017-04-20 16:41:50 -0600485 if (!fence_is_signaled(fence))
Lynus Vazc031a9b2017-01-25 13:00:13 +0530486 kcb = ERR_PTR(status);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700487 else
Lynus Vazc031a9b2017-01-25 13:00:13 +0530488 kcb = NULL;
489 fence_put(fence);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700490 }
491
Lynus Vazc031a9b2017-01-25 13:00:13 +0530492 return kcb;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700493}
494
Lynus Vazc031a9b2017-01-25 13:00:13 +0530495int kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_cb *kcb)
Shrenuj Bansala419c792016-10-20 14:05:11 -0700496{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530497 if (kcb == NULL)
Shrenuj Bansala419c792016-10-20 14:05:11 -0700498 return 0;
499
Lynus Vazc031a9b2017-01-25 13:00:13 +0530500 if (fence_remove_callback(kcb->fence, &kcb->fence_cb)) {
501 fence_put(kcb->fence);
502 kfree(kcb);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700503 return 1;
504 }
505 return 0;
506}
507
Shrenuj Bansala419c792016-10-20 14:05:11 -0700508struct kgsl_syncsource {
509 struct kref refcount;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530510 char name[KGSL_TIMELINE_NAME_LEN];
Shrenuj Bansala419c792016-10-20 14:05:11 -0700511 int id;
512 struct kgsl_process_private *private;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530513 struct list_head child_list_head;
514 spinlock_t lock;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700515};
516
Lynus Vazc031a9b2017-01-25 13:00:13 +0530517struct kgsl_syncsource_fence {
518 struct fence fence;
519 struct kgsl_syncsource *parent;
520 struct list_head child_list;
521};
522
523static const struct fence_ops kgsl_syncsource_fence_ops;
524
Shrenuj Bansala419c792016-10-20 14:05:11 -0700525long kgsl_ioctl_syncsource_create(struct kgsl_device_private *dev_priv,
526 unsigned int cmd, void *data)
527{
528 struct kgsl_syncsource *syncsource = NULL;
529 struct kgsl_syncsource_create *param = data;
530 int ret = -EINVAL;
531 int id = 0;
532 struct kgsl_process_private *private = dev_priv->process_priv;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530533 char name[KGSL_TIMELINE_NAME_LEN];
534
535 if (!kgsl_process_private_get(private))
536 return ret;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700537
538 syncsource = kzalloc(sizeof(*syncsource), GFP_KERNEL);
539 if (syncsource == NULL) {
540 ret = -ENOMEM;
541 goto out;
542 }
543
544 snprintf(name, sizeof(name), "kgsl-syncsource-pid-%d",
545 current->group_leader->pid);
546
Shrenuj Bansala419c792016-10-20 14:05:11 -0700547 kref_init(&syncsource->refcount);
Lynus Vazc031a9b2017-01-25 13:00:13 +0530548 strlcpy(syncsource->name, name, KGSL_TIMELINE_NAME_LEN);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700549 syncsource->private = private;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530550 INIT_LIST_HEAD(&syncsource->child_list_head);
551 spin_lock_init(&syncsource->lock);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700552
553 idr_preload(GFP_KERNEL);
554 spin_lock(&private->syncsource_lock);
555 id = idr_alloc(&private->syncsource_idr, syncsource, 1, 0, GFP_NOWAIT);
556 if (id > 0) {
557 syncsource->id = id;
558 param->id = id;
559 ret = 0;
560 } else {
561 ret = id;
562 }
563
564 spin_unlock(&private->syncsource_lock);
565 idr_preload_end();
566
567out:
568 if (ret) {
Lynus Vazc031a9b2017-01-25 13:00:13 +0530569 kgsl_process_private_put(private);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700570 kfree(syncsource);
571 }
572
573 return ret;
574}
575
576static struct kgsl_syncsource *
577kgsl_syncsource_get(struct kgsl_process_private *private, int id)
578{
579 int result = 0;
580 struct kgsl_syncsource *syncsource = NULL;
581
582 spin_lock(&private->syncsource_lock);
583
584 syncsource = idr_find(&private->syncsource_idr, id);
585 if (syncsource)
586 result = kref_get_unless_zero(&syncsource->refcount);
587
588 spin_unlock(&private->syncsource_lock);
589
590 return result ? syncsource : NULL;
591}
592
593static void kgsl_syncsource_destroy(struct kref *kref)
594{
595 struct kgsl_syncsource *syncsource = container_of(kref,
596 struct kgsl_syncsource,
597 refcount);
598
599 struct kgsl_process_private *private = syncsource->private;
600
Lynus Vazc031a9b2017-01-25 13:00:13 +0530601 /* Done with process private. Release the refcount */
602 kgsl_process_private_put(private);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700603
604 kfree(syncsource);
605}
606
607void kgsl_syncsource_put(struct kgsl_syncsource *syncsource)
608{
609 if (syncsource)
610 kref_put(&syncsource->refcount, kgsl_syncsource_destroy);
611}
612
Lynus Vazc031a9b2017-01-25 13:00:13 +0530613void kgsl_syncsource_cleanup(struct kgsl_process_private *private,
614 struct kgsl_syncsource *syncsource)
615{
616 struct kgsl_syncsource_fence *sfence, *next;
617
618 spin_lock(&private->syncsource_lock);
619 if (syncsource->id != 0) {
620 idr_remove(&private->syncsource_idr, syncsource->id);
621 syncsource->id = 0;
622 }
623 spin_unlock(&private->syncsource_lock);
624
625 /* Signal all fences to release any callbacks */
626 spin_lock(&syncsource->lock);
627
628 list_for_each_entry_safe(sfence, next, &syncsource->child_list_head,
629 child_list) {
630 fence_signal_locked(&sfence->fence);
631 list_del_init(&sfence->child_list);
632 }
633
634 spin_unlock(&syncsource->lock);
635
636 /* put reference from syncsource creation */
637 kgsl_syncsource_put(syncsource);
638}
639
Shrenuj Bansala419c792016-10-20 14:05:11 -0700640long kgsl_ioctl_syncsource_destroy(struct kgsl_device_private *dev_priv,
641 unsigned int cmd, void *data)
642{
643 struct kgsl_syncsource_destroy *param = data;
644 struct kgsl_syncsource *syncsource = NULL;
645 struct kgsl_process_private *private = dev_priv->process_priv;
646
647 spin_lock(&private->syncsource_lock);
648 syncsource = idr_find(&private->syncsource_idr, param->id);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700649 spin_unlock(&private->syncsource_lock);
650
651 if (syncsource == NULL)
652 return -EINVAL;
653
Lynus Vazc031a9b2017-01-25 13:00:13 +0530654 kgsl_syncsource_cleanup(private, syncsource);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700655 return 0;
656}
657
658long kgsl_ioctl_syncsource_create_fence(struct kgsl_device_private *dev_priv,
659 unsigned int cmd, void *data)
660{
661 struct kgsl_syncsource_create_fence *param = data;
662 struct kgsl_syncsource *syncsource = NULL;
663 int ret = -EINVAL;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530664 struct kgsl_syncsource_fence *sfence = NULL;
665 struct sync_file *sync_file = NULL;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700666 int fd = -1;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700667
Lynus Vazc031a9b2017-01-25 13:00:13 +0530668 /*
669 * Take a refcount that is released when the fence is released
670 * (or if fence can't be added to the syncsource).
671 */
Shrenuj Bansala419c792016-10-20 14:05:11 -0700672 syncsource = kgsl_syncsource_get(dev_priv->process_priv,
673 param->id);
674 if (syncsource == NULL)
675 goto out;
676
Lynus Vazc031a9b2017-01-25 13:00:13 +0530677 sfence = kzalloc(sizeof(*sfence), GFP_KERNEL);
678 if (sfence == NULL) {
679 ret = -ENOMEM;
680 goto out;
681 }
682 sfence->parent = syncsource;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700683
Lynus Vazc031a9b2017-01-25 13:00:13 +0530684 /* Use a new fence context for each fence */
685 fence_init(&sfence->fence, &kgsl_syncsource_fence_ops,
686 &syncsource->lock, fence_context_alloc(1), 1);
687
688 sync_file = sync_file_create(&sfence->fence);
689
690 if (sync_file == NULL) {
691 KGSL_DRV_ERR(dev_priv->device, "Create sync_file failed\n");
Shrenuj Bansala419c792016-10-20 14:05:11 -0700692 ret = -ENOMEM;
693 goto out;
694 }
695
696 fd = get_unused_fd_flags(0);
697 if (fd < 0) {
698 ret = -EBADF;
699 goto out;
700 }
701 ret = 0;
702
Lynus Vazc031a9b2017-01-25 13:00:13 +0530703 fd_install(fd, sync_file->file);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700704
705 param->fence_fd = fd;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530706
707 spin_lock(&syncsource->lock);
708 list_add_tail(&sfence->child_list, &syncsource->child_list_head);
709 spin_unlock(&syncsource->lock);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700710out:
Lynus Vaz9d6334b2017-06-27 14:57:56 +0530711 /*
712 * We're transferring ownership of the fence to the sync file.
713 * The sync file takes an extra refcount when it is created, so put
714 * our refcount.
715 */
716 if (sync_file)
717 fence_put(&sfence->fence);
718
Shrenuj Bansala419c792016-10-20 14:05:11 -0700719 if (ret) {
Lynus Vazc031a9b2017-01-25 13:00:13 +0530720 if (sync_file)
721 fput(sync_file->file);
722 else if (sfence)
723 fence_put(&sfence->fence);
724 kgsl_syncsource_put(syncsource);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700725 }
Lynus Vazc031a9b2017-01-25 13:00:13 +0530726
727 return ret;
728}
729
730static int kgsl_syncsource_signal(struct kgsl_syncsource *syncsource,
731 struct fence *fence)
732{
733 struct kgsl_syncsource_fence *sfence, *next;
734 int ret = -EINVAL;
735
736 spin_lock(&syncsource->lock);
737
738 list_for_each_entry_safe(sfence, next, &syncsource->child_list_head,
739 child_list) {
740 if (fence == &sfence->fence) {
741 fence_signal_locked(fence);
742 list_del_init(&sfence->child_list);
743
744 ret = 0;
745 break;
746 }
747 }
748
749 spin_unlock(&syncsource->lock);
750
Shrenuj Bansala419c792016-10-20 14:05:11 -0700751 return ret;
752}
753
754long kgsl_ioctl_syncsource_signal_fence(struct kgsl_device_private *dev_priv,
755 unsigned int cmd, void *data)
756{
757 int ret = -EINVAL;
758 struct kgsl_syncsource_signal_fence *param = data;
759 struct kgsl_syncsource *syncsource = NULL;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530760 struct fence *fence = NULL;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700761
762 syncsource = kgsl_syncsource_get(dev_priv->process_priv,
763 param->id);
764 if (syncsource == NULL)
765 goto out;
766
Lynus Vazc031a9b2017-01-25 13:00:13 +0530767 fence = sync_file_get_fence(param->fence_fd);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700768 if (fence == NULL) {
769 ret = -EBADF;
770 goto out;
771 }
772
Lynus Vazc031a9b2017-01-25 13:00:13 +0530773 ret = kgsl_syncsource_signal(syncsource, fence);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700774out:
775 if (fence)
Lynus Vazc031a9b2017-01-25 13:00:13 +0530776 fence_put(fence);
777 if (syncsource)
778 kgsl_syncsource_put(syncsource);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700779 return ret;
780}
Lynus Vazc031a9b2017-01-25 13:00:13 +0530781
782static void kgsl_syncsource_fence_release(struct fence *fence)
783{
784 struct kgsl_syncsource_fence *sfence =
785 (struct kgsl_syncsource_fence *)fence;
786
787 /* Signal if it's not signaled yet */
788 kgsl_syncsource_signal(sfence->parent, fence);
789
790 /* Release the refcount on the syncsource */
791 kgsl_syncsource_put(sfence->parent);
792
793 kfree(sfence);
794}
795
796static const char *kgsl_syncsource_get_timeline_name(struct fence *fence)
797{
798 struct kgsl_syncsource_fence *sfence =
799 (struct kgsl_syncsource_fence *)fence;
800 struct kgsl_syncsource *syncsource = sfence->parent;
801
802 return syncsource->name;
803}
804
805static bool kgsl_syncsource_enable_signaling(struct fence *fence)
806{
807 return true;
808}
809
810static const char *kgsl_syncsource_driver_name(struct fence *fence)
811{
812 return "kgsl-syncsource-timeline";
813}
814
Lynus Vaz6aa3f5a2017-04-26 19:29:05 +0530815static void kgsl_syncsource_fence_value_str(struct fence *fence,
816 char *str, int size)
817{
818 /*
819 * Each fence is independent of the others on the same timeline.
820 * We use a different context for each of them.
821 */
822 snprintf(str, size, "%llu", fence->context);
823}
824
Lynus Vazc031a9b2017-01-25 13:00:13 +0530825static const struct fence_ops kgsl_syncsource_fence_ops = {
826 .get_driver_name = kgsl_syncsource_driver_name,
827 .get_timeline_name = kgsl_syncsource_get_timeline_name,
828 .enable_signaling = kgsl_syncsource_enable_signaling,
829 .wait = fence_default_wait,
830 .release = kgsl_syncsource_fence_release,
Lynus Vaz6aa3f5a2017-04-26 19:29:05 +0530831
832 .fence_value_str = kgsl_syncsource_fence_value_str,
Lynus Vazc031a9b2017-01-25 13:00:13 +0530833};
834