MALI: utgard: rockchip: remove code depending on rk_dvfs_module
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / arm / midgard / mali_kbase_sync.c
1 /*
2  *
3  * (C) COPYRIGHT 2012-2015 ARM Limited. All rights reserved.
4  *
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
8  * of such GNU licence.
9  *
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.
13  *
14  */
15
16
17
18 #ifdef CONFIG_SYNC
19
20 #include <linux/seq_file.h>
21 #include "sync.h"
22 #include <mali_kbase.h>
23 #include <mali_kbase_sync.h>
24
25 struct mali_sync_timeline {
26         struct sync_timeline timeline;
27         atomic_t counter;
28         atomic_t signalled;
29 };
30
31 struct mali_sync_pt {
32         struct sync_pt pt;
33         int order;
34         int result;
35 };
36
37 static struct mali_sync_timeline *to_mali_sync_timeline(struct sync_timeline *timeline)
38 {
39         return container_of(timeline, struct mali_sync_timeline, timeline);
40 }
41
42 static struct mali_sync_pt *to_mali_sync_pt(struct sync_pt *pt)
43 {
44         return container_of(pt, struct mali_sync_pt, pt);
45 }
46
47 static struct sync_pt *timeline_dup(struct sync_pt *pt)
48 {
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));
52
53         if (!new_pt)
54                 return NULL;
55
56         new_mpt = to_mali_sync_pt(new_pt);
57         new_mpt->order = mpt->order;
58         new_mpt->result = mpt->result;
59
60         return new_pt;
61 }
62
63 static int timeline_has_signaled(struct sync_pt *pt)
64 {
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;
68
69         int diff = atomic_read(&mtl->signalled) - mpt->order;
70
71         if (diff >= 0)
72                 return (result < 0) ? result : 1;
73
74         return 0;
75 }
76
77 static int timeline_compare(struct sync_pt *a, struct sync_pt *b)
78 {
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);
81
82         int diff = ma->order - mb->order;
83
84         if (diff == 0)
85                 return 0;
86
87         return (diff < 0) ? -1 : 1;
88 }
89
90 static void timeline_value_str(struct sync_timeline *timeline, char *str,
91                                int size)
92 {
93         struct mali_sync_timeline *mtl = to_mali_sync_timeline(timeline);
94
95         snprintf(str, size, "%d", atomic_read(&mtl->signalled));
96 }
97
98 static void pt_value_str(struct sync_pt *pt, char *str, int size)
99 {
100         struct mali_sync_pt *mpt = to_mali_sync_pt(pt);
101
102         snprintf(str, size, "%d(%d)", mpt->order, mpt->result);
103 }
104
105 static struct sync_timeline_ops mali_timeline_ops = {
106         .driver_name = "Mali",
107         .dup = timeline_dup,
108         .has_signaled = timeline_has_signaled,
109         .compare = timeline_compare,
110         .timeline_value_str = timeline_value_str,
111         .pt_value_str       = pt_value_str,
112 };
113
114 int kbase_sync_timeline_is_ours(struct sync_timeline *timeline)
115 {
116         return timeline->ops == &mali_timeline_ops;
117 }
118
119 struct sync_timeline *kbase_sync_timeline_alloc(const char *name)
120 {
121         struct sync_timeline *tl;
122         struct mali_sync_timeline *mtl;
123
124         tl = sync_timeline_create(&mali_timeline_ops, sizeof(struct mali_sync_timeline), name);
125         if (!tl)
126                 return NULL;
127
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);
132
133         return tl;
134 }
135
136 struct sync_pt *kbase_sync_pt_alloc(struct sync_timeline *parent)
137 {
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;
141
142         if (!pt)
143                 return NULL;
144
145         mpt = to_mali_sync_pt(pt);
146         mpt->order = atomic_inc_return(&mtl->counter);
147         mpt->result = 0;
148
149         return pt;
150 }
151
152 void kbase_sync_signal_pt(struct sync_pt *pt, int result)
153 {
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));
156         int signalled;
157         int diff;
158
159         mpt->result = result;
160
161         do {
162                 signalled = atomic_read(&mtl->signalled);
163
164                 diff = signalled - mpt->order;
165
166                 if (diff > 0) {
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.
173                          */
174 #ifdef CONFIG_MALI_DEBUG
175                         pr_err("Fences were triggered in a different order to allocation!");
176 #endif                          /* CONFIG_MALI_DEBUG */
177                         return;
178                 }
179         } while (atomic_cmpxchg(&mtl->signalled, signalled, mpt->order) != signalled);
180 }
181
182 #endif                          /* CONFIG_SYNC */