3 * (C) COPYRIGHT 2012-2015 ARM Limited. All rights reserved.
5 * This program is free software and is provided to you under the terms of the
6 * GNU General Public License version 2 as published by the Free Software
7 * Foundation, and any use by you of this program is subject to the terms
10 * A copy of the licence is included with the program, and can also be obtained
11 * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
12 * Boston, MA 02110-1301, USA.
20 #include <linux/seq_file.h>
22 #include <mali_kbase.h>
23 #include <mali_kbase_sync.h>
25 struct mali_sync_timeline {
26 struct sync_timeline timeline;
37 static struct mali_sync_timeline *to_mali_sync_timeline(struct sync_timeline *timeline)
39 return container_of(timeline, struct mali_sync_timeline, timeline);
42 static struct mali_sync_pt *to_mali_sync_pt(struct sync_pt *pt)
44 return container_of(pt, struct mali_sync_pt, pt);
47 static struct sync_pt *timeline_dup(struct sync_pt *pt)
49 struct mali_sync_pt *mpt = to_mali_sync_pt(pt);
50 struct mali_sync_pt *new_mpt;
51 struct sync_pt *new_pt = sync_pt_create(sync_pt_parent(pt), sizeof(struct mali_sync_pt));
56 new_mpt = to_mali_sync_pt(new_pt);
57 new_mpt->order = mpt->order;
58 new_mpt->result = mpt->result;
63 static int timeline_has_signaled(struct sync_pt *pt)
65 struct mali_sync_pt *mpt = to_mali_sync_pt(pt);
66 struct mali_sync_timeline *mtl = to_mali_sync_timeline(sync_pt_parent(pt));
67 int result = mpt->result;
69 int diff = atomic_read(&mtl->signalled) - mpt->order;
72 return (result < 0) ? result : 1;
77 static int timeline_compare(struct sync_pt *a, struct sync_pt *b)
79 struct mali_sync_pt *ma = container_of(a, struct mali_sync_pt, pt);
80 struct mali_sync_pt *mb = container_of(b, struct mali_sync_pt, pt);
82 int diff = ma->order - mb->order;
87 return (diff < 0) ? -1 : 1;
90 static void timeline_value_str(struct sync_timeline *timeline, char *str,
93 struct mali_sync_timeline *mtl = to_mali_sync_timeline(timeline);
95 snprintf(str, size, "%d", atomic_read(&mtl->signalled));
98 static void pt_value_str(struct sync_pt *pt, char *str, int size)
100 struct mali_sync_pt *mpt = to_mali_sync_pt(pt);
102 snprintf(str, size, "%d(%d)", mpt->order, mpt->result);
105 static struct sync_timeline_ops mali_timeline_ops = {
106 .driver_name = "Mali",
108 .has_signaled = timeline_has_signaled,
109 .compare = timeline_compare,
110 .timeline_value_str = timeline_value_str,
111 .pt_value_str = pt_value_str,
114 int kbase_sync_timeline_is_ours(struct sync_timeline *timeline)
116 return timeline->ops == &mali_timeline_ops;
119 struct sync_timeline *kbase_sync_timeline_alloc(const char *name)
121 struct sync_timeline *tl;
122 struct mali_sync_timeline *mtl;
124 tl = sync_timeline_create(&mali_timeline_ops, sizeof(struct mali_sync_timeline), name);
128 /* Set the counter in our private struct */
129 mtl = to_mali_sync_timeline(tl);
130 atomic_set(&mtl->counter, 0);
131 atomic_set(&mtl->signalled, 0);
136 struct sync_pt *kbase_sync_pt_alloc(struct sync_timeline *parent)
138 struct sync_pt *pt = sync_pt_create(parent, sizeof(struct mali_sync_pt));
139 struct mali_sync_timeline *mtl = to_mali_sync_timeline(parent);
140 struct mali_sync_pt *mpt;
145 mpt = to_mali_sync_pt(pt);
146 mpt->order = atomic_inc_return(&mtl->counter);
152 void kbase_sync_signal_pt(struct sync_pt *pt, int result)
154 struct mali_sync_pt *mpt = to_mali_sync_pt(pt);
155 struct mali_sync_timeline *mtl = to_mali_sync_timeline(sync_pt_parent(pt));
159 mpt->result = result;
162 signalled = atomic_read(&mtl->signalled);
164 diff = signalled - mpt->order;
167 /* The timeline is already at or ahead of this point.
168 * This should not happen unless userspace has been
169 * signalling fences out of order, so warn but don't
170 * violate the sync_pt API.
171 * The warning is only in debug builds to prevent
172 * a malicious user being able to spam dmesg.
174 #ifdef CONFIG_MALI_DEBUG
175 pr_err("Fences were triggered in a different order to allocation!");
176 #endif /* CONFIG_MALI_DEBUG */
179 } while (atomic_cmpxchg(&mtl->signalled, signalled, mpt->order) != signalled);
182 #endif /* CONFIG_SYNC */