blob: d75ec9df86227434f8f318ed5596f3e44dd6ff9d [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 Vaz8795cc62017-07-28 21:33:11 +0530373 if (!kref_get_unless_zero(&ktimeline->kref))
374 return;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530375
376 spin_lock_irqsave(&ktimeline->lock, flags);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700377 if (timestamp_cmp(timestamp, ktimeline->last_timestamp) > 0)
378 ktimeline->last_timestamp = timestamp;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700379
Lynus Vazc031a9b2017-01-25 13:00:13 +0530380 list_for_each_entry_safe(kfence, next, &ktimeline->child_list_head,
381 child_list) {
382 if (fence_is_signaled_locked(&kfence->fence)) {
Lynus Vazc50d6202017-03-23 13:42:58 +0530383 list_del_init(&kfence->child_list);
Lynus Vazc031a9b2017-01-25 13:00:13 +0530384 fence_put(&kfence->fence);
385 }
386 }
387
388 spin_unlock_irqrestore(&ktimeline->lock, flags);
389 kgsl_sync_timeline_put(ktimeline);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700390}
391
392void kgsl_sync_timeline_destroy(struct kgsl_context *context)
393{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530394 kfree(context->ktimeline);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700395}
396
Lynus Vazc031a9b2017-01-25 13:00:13 +0530397static void kgsl_sync_timeline_release(struct kref *kref)
Shrenuj Bansala419c792016-10-20 14:05:11 -0700398{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530399 struct kgsl_sync_timeline *ktimeline =
400 container_of(kref, struct kgsl_sync_timeline, kref);
401
402 /*
403 * Only put the context refcount here. The context destroy function
404 * will call kgsl_sync_timeline_destroy() to kfree it
405 */
406 kgsl_context_put(ktimeline->context);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700407}
408
Lynus Vazc031a9b2017-01-25 13:00:13 +0530409void kgsl_sync_timeline_put(struct kgsl_sync_timeline *ktimeline)
410{
411 if (ktimeline)
412 kref_put(&ktimeline->kref, kgsl_sync_timeline_release);
413}
414
415static const struct fence_ops kgsl_sync_fence_ops = {
416 .get_driver_name = kgsl_sync_fence_driver_name,
417 .get_timeline_name = kgsl_sync_timeline_name,
418 .enable_signaling = kgsl_enable_signaling,
419 .signaled = kgsl_sync_fence_has_signaled,
420 .wait = fence_default_wait,
421 .release = kgsl_sync_fence_release,
422
423 .fence_value_str = kgsl_sync_fence_value_str,
424 .timeline_value_str = kgsl_sync_timeline_value_str,
425};
426
427static void kgsl_sync_fence_callback(struct fence *fence, struct fence_cb *cb)
428{
429 struct kgsl_sync_fence_cb *kcb = (struct kgsl_sync_fence_cb *)cb;
430
431 kcb->func(kcb->priv);
432 fence_put(kcb->fence);
433 kfree(kcb);
434}
435
Lynus Vaze99b92b2017-04-24 18:04:54 +0530436static void kgsl_get_fence_name(struct fence *fence,
437 char *fence_name, int name_len)
438{
439 char *ptr = fence_name;
440 char *last = fence_name + name_len;
441
442 ptr += snprintf(ptr, last - ptr, "%s %s",
443 fence->ops->get_driver_name(fence),
444 fence->ops->get_timeline_name(fence));
445
446 if ((ptr + 2) >= last)
447 return;
448
449 if (fence->ops->fence_value_str) {
450 ptr += snprintf(ptr, last - ptr, ": ");
451 fence->ops->fence_value_str(fence, ptr, last - ptr);
452 }
453}
454
Lynus Vazc031a9b2017-01-25 13:00:13 +0530455struct kgsl_sync_fence_cb *kgsl_sync_fence_async_wait(int fd,
Lynus Vaze99b92b2017-04-24 18:04:54 +0530456 void (*func)(void *priv), void *priv, char *fence_name, int name_len)
Shrenuj Bansala419c792016-10-20 14:05:11 -0700457{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530458 struct kgsl_sync_fence_cb *kcb;
459 struct fence *fence;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700460 int status;
461
Lynus Vazc031a9b2017-01-25 13:00:13 +0530462 fence = sync_file_get_fence(fd);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700463 if (fence == NULL)
464 return ERR_PTR(-EINVAL);
465
Lynus Vazc031a9b2017-01-25 13:00:13 +0530466 /* create the callback */
467 kcb = kzalloc(sizeof(*kcb), GFP_ATOMIC);
468 if (kcb == NULL) {
469 fence_put(fence);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700470 return ERR_PTR(-ENOMEM);
471 }
472
Lynus Vazc031a9b2017-01-25 13:00:13 +0530473 kcb->fence = fence;
474 kcb->priv = priv;
475 kcb->func = func;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700476
Lynus Vaze99b92b2017-04-24 18:04:54 +0530477 if (fence_name)
478 kgsl_get_fence_name(fence, fence_name, name_len);
479
Shrenuj Bansala419c792016-10-20 14:05:11 -0700480 /* if status then error or signaled */
Lynus Vazc031a9b2017-01-25 13:00:13 +0530481 status = fence_add_callback(fence, &kcb->fence_cb,
482 kgsl_sync_fence_callback);
483
Shrenuj Bansala419c792016-10-20 14:05:11 -0700484 if (status) {
Lynus Vazc031a9b2017-01-25 13:00:13 +0530485 kfree(kcb);
Harshdeep Dhatt0ed60a42017-04-20 16:41:50 -0600486 if (!fence_is_signaled(fence))
Lynus Vazc031a9b2017-01-25 13:00:13 +0530487 kcb = ERR_PTR(status);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700488 else
Lynus Vazc031a9b2017-01-25 13:00:13 +0530489 kcb = NULL;
490 fence_put(fence);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700491 }
492
Lynus Vazc031a9b2017-01-25 13:00:13 +0530493 return kcb;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700494}
495
Lynus Vazc031a9b2017-01-25 13:00:13 +0530496int kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_cb *kcb)
Shrenuj Bansala419c792016-10-20 14:05:11 -0700497{
Lynus Vazc031a9b2017-01-25 13:00:13 +0530498 if (kcb == NULL)
Shrenuj Bansala419c792016-10-20 14:05:11 -0700499 return 0;
500
Lynus Vazc031a9b2017-01-25 13:00:13 +0530501 if (fence_remove_callback(kcb->fence, &kcb->fence_cb)) {
502 fence_put(kcb->fence);
503 kfree(kcb);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700504 return 1;
505 }
506 return 0;
507}
508
Shrenuj Bansala419c792016-10-20 14:05:11 -0700509struct kgsl_syncsource {
510 struct kref refcount;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530511 char name[KGSL_TIMELINE_NAME_LEN];
Shrenuj Bansala419c792016-10-20 14:05:11 -0700512 int id;
513 struct kgsl_process_private *private;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530514 struct list_head child_list_head;
515 spinlock_t lock;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700516};
517
Lynus Vazc031a9b2017-01-25 13:00:13 +0530518struct kgsl_syncsource_fence {
519 struct fence fence;
520 struct kgsl_syncsource *parent;
521 struct list_head child_list;
522};
523
524static const struct fence_ops kgsl_syncsource_fence_ops;
525
Shrenuj Bansala419c792016-10-20 14:05:11 -0700526long kgsl_ioctl_syncsource_create(struct kgsl_device_private *dev_priv,
527 unsigned int cmd, void *data)
528{
529 struct kgsl_syncsource *syncsource = NULL;
530 struct kgsl_syncsource_create *param = data;
531 int ret = -EINVAL;
532 int id = 0;
533 struct kgsl_process_private *private = dev_priv->process_priv;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530534 char name[KGSL_TIMELINE_NAME_LEN];
535
536 if (!kgsl_process_private_get(private))
537 return ret;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700538
539 syncsource = kzalloc(sizeof(*syncsource), GFP_KERNEL);
540 if (syncsource == NULL) {
541 ret = -ENOMEM;
542 goto out;
543 }
544
545 snprintf(name, sizeof(name), "kgsl-syncsource-pid-%d",
546 current->group_leader->pid);
547
Shrenuj Bansala419c792016-10-20 14:05:11 -0700548 kref_init(&syncsource->refcount);
Lynus Vazc031a9b2017-01-25 13:00:13 +0530549 strlcpy(syncsource->name, name, KGSL_TIMELINE_NAME_LEN);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700550 syncsource->private = private;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530551 INIT_LIST_HEAD(&syncsource->child_list_head);
552 spin_lock_init(&syncsource->lock);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700553
554 idr_preload(GFP_KERNEL);
555 spin_lock(&private->syncsource_lock);
556 id = idr_alloc(&private->syncsource_idr, syncsource, 1, 0, GFP_NOWAIT);
557 if (id > 0) {
558 syncsource->id = id;
559 param->id = id;
560 ret = 0;
561 } else {
562 ret = id;
563 }
564
565 spin_unlock(&private->syncsource_lock);
566 idr_preload_end();
567
568out:
569 if (ret) {
Lynus Vazc031a9b2017-01-25 13:00:13 +0530570 kgsl_process_private_put(private);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700571 kfree(syncsource);
572 }
573
574 return ret;
575}
576
577static struct kgsl_syncsource *
578kgsl_syncsource_get(struct kgsl_process_private *private, int id)
579{
580 int result = 0;
581 struct kgsl_syncsource *syncsource = NULL;
582
583 spin_lock(&private->syncsource_lock);
584
585 syncsource = idr_find(&private->syncsource_idr, id);
586 if (syncsource)
587 result = kref_get_unless_zero(&syncsource->refcount);
588
589 spin_unlock(&private->syncsource_lock);
590
591 return result ? syncsource : NULL;
592}
593
594static void kgsl_syncsource_destroy(struct kref *kref)
595{
596 struct kgsl_syncsource *syncsource = container_of(kref,
597 struct kgsl_syncsource,
598 refcount);
599
600 struct kgsl_process_private *private = syncsource->private;
601
Lynus Vazc031a9b2017-01-25 13:00:13 +0530602 /* Done with process private. Release the refcount */
603 kgsl_process_private_put(private);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700604
605 kfree(syncsource);
606}
607
608void kgsl_syncsource_put(struct kgsl_syncsource *syncsource)
609{
610 if (syncsource)
611 kref_put(&syncsource->refcount, kgsl_syncsource_destroy);
612}
613
Lynus Vazc031a9b2017-01-25 13:00:13 +0530614void kgsl_syncsource_cleanup(struct kgsl_process_private *private,
615 struct kgsl_syncsource *syncsource)
616{
617 struct kgsl_syncsource_fence *sfence, *next;
618
619 spin_lock(&private->syncsource_lock);
620 if (syncsource->id != 0) {
621 idr_remove(&private->syncsource_idr, syncsource->id);
622 syncsource->id = 0;
623 }
624 spin_unlock(&private->syncsource_lock);
625
626 /* Signal all fences to release any callbacks */
627 spin_lock(&syncsource->lock);
628
629 list_for_each_entry_safe(sfence, next, &syncsource->child_list_head,
630 child_list) {
631 fence_signal_locked(&sfence->fence);
632 list_del_init(&sfence->child_list);
633 }
634
635 spin_unlock(&syncsource->lock);
636
637 /* put reference from syncsource creation */
638 kgsl_syncsource_put(syncsource);
639}
640
Shrenuj Bansala419c792016-10-20 14:05:11 -0700641long kgsl_ioctl_syncsource_destroy(struct kgsl_device_private *dev_priv,
642 unsigned int cmd, void *data)
643{
644 struct kgsl_syncsource_destroy *param = data;
645 struct kgsl_syncsource *syncsource = NULL;
646 struct kgsl_process_private *private = dev_priv->process_priv;
647
648 spin_lock(&private->syncsource_lock);
649 syncsource = idr_find(&private->syncsource_idr, param->id);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700650 spin_unlock(&private->syncsource_lock);
651
652 if (syncsource == NULL)
653 return -EINVAL;
654
Lynus Vazc031a9b2017-01-25 13:00:13 +0530655 kgsl_syncsource_cleanup(private, syncsource);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700656 return 0;
657}
658
659long kgsl_ioctl_syncsource_create_fence(struct kgsl_device_private *dev_priv,
660 unsigned int cmd, void *data)
661{
662 struct kgsl_syncsource_create_fence *param = data;
663 struct kgsl_syncsource *syncsource = NULL;
664 int ret = -EINVAL;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530665 struct kgsl_syncsource_fence *sfence = NULL;
666 struct sync_file *sync_file = NULL;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700667 int fd = -1;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700668
Lynus Vazc031a9b2017-01-25 13:00:13 +0530669 /*
670 * Take a refcount that is released when the fence is released
671 * (or if fence can't be added to the syncsource).
672 */
Shrenuj Bansala419c792016-10-20 14:05:11 -0700673 syncsource = kgsl_syncsource_get(dev_priv->process_priv,
674 param->id);
675 if (syncsource == NULL)
676 goto out;
677
Lynus Vazc031a9b2017-01-25 13:00:13 +0530678 sfence = kzalloc(sizeof(*sfence), GFP_KERNEL);
679 if (sfence == NULL) {
680 ret = -ENOMEM;
681 goto out;
682 }
683 sfence->parent = syncsource;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700684
Lynus Vazc031a9b2017-01-25 13:00:13 +0530685 /* Use a new fence context for each fence */
686 fence_init(&sfence->fence, &kgsl_syncsource_fence_ops,
687 &syncsource->lock, fence_context_alloc(1), 1);
688
689 sync_file = sync_file_create(&sfence->fence);
690
691 if (sync_file == NULL) {
692 KGSL_DRV_ERR(dev_priv->device, "Create sync_file failed\n");
Shrenuj Bansala419c792016-10-20 14:05:11 -0700693 ret = -ENOMEM;
694 goto out;
695 }
696
697 fd = get_unused_fd_flags(0);
698 if (fd < 0) {
699 ret = -EBADF;
700 goto out;
701 }
702 ret = 0;
703
Lynus Vazc031a9b2017-01-25 13:00:13 +0530704 fd_install(fd, sync_file->file);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700705
706 param->fence_fd = fd;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530707
708 spin_lock(&syncsource->lock);
709 list_add_tail(&sfence->child_list, &syncsource->child_list_head);
710 spin_unlock(&syncsource->lock);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700711out:
Lynus Vaz9d6334b2017-06-27 14:57:56 +0530712 /*
713 * We're transferring ownership of the fence to the sync file.
714 * The sync file takes an extra refcount when it is created, so put
715 * our refcount.
716 */
717 if (sync_file)
718 fence_put(&sfence->fence);
719
Shrenuj Bansala419c792016-10-20 14:05:11 -0700720 if (ret) {
Lynus Vazc031a9b2017-01-25 13:00:13 +0530721 if (sync_file)
722 fput(sync_file->file);
723 else if (sfence)
724 fence_put(&sfence->fence);
725 kgsl_syncsource_put(syncsource);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700726 }
Lynus Vazc031a9b2017-01-25 13:00:13 +0530727
728 return ret;
729}
730
731static int kgsl_syncsource_signal(struct kgsl_syncsource *syncsource,
732 struct fence *fence)
733{
734 struct kgsl_syncsource_fence *sfence, *next;
735 int ret = -EINVAL;
736
737 spin_lock(&syncsource->lock);
738
739 list_for_each_entry_safe(sfence, next, &syncsource->child_list_head,
740 child_list) {
741 if (fence == &sfence->fence) {
742 fence_signal_locked(fence);
743 list_del_init(&sfence->child_list);
744
745 ret = 0;
746 break;
747 }
748 }
749
750 spin_unlock(&syncsource->lock);
751
Shrenuj Bansala419c792016-10-20 14:05:11 -0700752 return ret;
753}
754
755long kgsl_ioctl_syncsource_signal_fence(struct kgsl_device_private *dev_priv,
756 unsigned int cmd, void *data)
757{
758 int ret = -EINVAL;
759 struct kgsl_syncsource_signal_fence *param = data;
760 struct kgsl_syncsource *syncsource = NULL;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530761 struct fence *fence = NULL;
Shrenuj Bansala419c792016-10-20 14:05:11 -0700762
763 syncsource = kgsl_syncsource_get(dev_priv->process_priv,
764 param->id);
765 if (syncsource == NULL)
766 goto out;
767
Lynus Vazc031a9b2017-01-25 13:00:13 +0530768 fence = sync_file_get_fence(param->fence_fd);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700769 if (fence == NULL) {
770 ret = -EBADF;
771 goto out;
772 }
773
Lynus Vazc031a9b2017-01-25 13:00:13 +0530774 ret = kgsl_syncsource_signal(syncsource, fence);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700775out:
776 if (fence)
Lynus Vazc031a9b2017-01-25 13:00:13 +0530777 fence_put(fence);
778 if (syncsource)
779 kgsl_syncsource_put(syncsource);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700780 return ret;
781}
Lynus Vazc031a9b2017-01-25 13:00:13 +0530782
783static void kgsl_syncsource_fence_release(struct fence *fence)
784{
785 struct kgsl_syncsource_fence *sfence =
786 (struct kgsl_syncsource_fence *)fence;
787
788 /* Signal if it's not signaled yet */
789 kgsl_syncsource_signal(sfence->parent, fence);
790
791 /* Release the refcount on the syncsource */
792 kgsl_syncsource_put(sfence->parent);
793
794 kfree(sfence);
795}
796
797static const char *kgsl_syncsource_get_timeline_name(struct fence *fence)
798{
799 struct kgsl_syncsource_fence *sfence =
800 (struct kgsl_syncsource_fence *)fence;
801 struct kgsl_syncsource *syncsource = sfence->parent;
802
803 return syncsource->name;
804}
805
806static bool kgsl_syncsource_enable_signaling(struct fence *fence)
807{
808 return true;
809}
810
811static const char *kgsl_syncsource_driver_name(struct fence *fence)
812{
813 return "kgsl-syncsource-timeline";
814}
815
Lynus Vaz6aa3f5a2017-04-26 19:29:05 +0530816static void kgsl_syncsource_fence_value_str(struct fence *fence,
817 char *str, int size)
818{
819 /*
820 * Each fence is independent of the others on the same timeline.
821 * We use a different context for each of them.
822 */
823 snprintf(str, size, "%llu", fence->context);
824}
825
Lynus Vazc031a9b2017-01-25 13:00:13 +0530826static const struct fence_ops kgsl_syncsource_fence_ops = {
827 .get_driver_name = kgsl_syncsource_driver_name,
828 .get_timeline_name = kgsl_syncsource_get_timeline_name,
829 .enable_signaling = kgsl_syncsource_enable_signaling,
830 .wait = fence_default_wait,
831 .release = kgsl_syncsource_fence_release,
Lynus Vaz6aa3f5a2017-04-26 19:29:05 +0530832
833 .fence_value_str = kgsl_syncsource_fence_value_str,
Lynus Vazc031a9b2017-01-25 13:00:13 +0530834};
835