ARM64: DTS: Add rk3399-firefly uart4 device, node as /dev/ttyS1
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / arm / mali400 / mali / linux / mali_osk_locks.c
1 /*
2  * Copyright (C) 2010-2014, 2016 ARM Limited. All rights reserved.
3  * 
4  * This program is free software and is provided to you under the terms of the GNU General Public License version 2
5  * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
6  * 
7  * A copy of the licence is included with the program, and can also be obtained from Free Software
8  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
9  */
10
11 /**
12  * @file mali_osk_locks.c
13  * Implemenation of the OS abstraction layer for the kernel device driver
14  */
15
16 #include "mali_osk_locks.h"
17 #include "mali_kernel_common.h"
18 #include "mali_osk.h"
19
20
21 #ifdef DEBUG
22 #ifdef LOCK_ORDER_CHECKING
23 static DEFINE_SPINLOCK(lock_tracking_lock);
24 static mali_bool add_lock_to_log_and_check(struct _mali_osk_lock_debug_s *lock, uint32_t tid);
25 static void remove_lock_from_log(struct _mali_osk_lock_debug_s *lock, uint32_t tid);
26 static const char *const lock_order_to_string(_mali_osk_lock_order_t order);
27 #endif /* LOCK_ORDER_CHECKING */
28
29 void _mali_osk_locks_debug_init(struct _mali_osk_lock_debug_s *checker, _mali_osk_lock_flags_t flags, _mali_osk_lock_order_t order)
30 {
31         checker->orig_flags = flags;
32         checker->owner = 0;
33
34 #ifdef LOCK_ORDER_CHECKING
35         checker->order = order;
36         checker->next = NULL;
37 #endif
38 }
39
40 void _mali_osk_locks_debug_add(struct _mali_osk_lock_debug_s *checker)
41 {
42         checker->owner = _mali_osk_get_tid();
43
44 #ifdef LOCK_ORDER_CHECKING
45         if (!(checker->orig_flags & _MALI_OSK_LOCKFLAG_UNORDERED)) {
46                 if (!add_lock_to_log_and_check(checker, _mali_osk_get_tid())) {
47                         printk(KERN_ERR "%d: ERROR lock %p taken while holding a lock of a higher order.\n",
48                                _mali_osk_get_tid(), checker);
49                         dump_stack();
50                 }
51         }
52 #endif
53 }
54
55 void _mali_osk_locks_debug_remove(struct _mali_osk_lock_debug_s *checker)
56 {
57
58 #ifdef LOCK_ORDER_CHECKING
59         if (!(checker->orig_flags & _MALI_OSK_LOCKFLAG_UNORDERED)) {
60                 remove_lock_from_log(checker, _mali_osk_get_tid());
61         }
62 #endif
63         checker->owner = 0;
64 }
65
66
67 #ifdef LOCK_ORDER_CHECKING
68 /* Lock order checking
69  * -------------------
70  *
71  * To assure that lock ordering scheme defined by _mali_osk_lock_order_t is strictly adhered to, the
72  * following function will, together with a linked list and some extra members in _mali_osk_lock_debug_s,
73  * make sure that a lock that is taken has a higher order than the current highest-order lock a
74  * thread holds.
75  *
76  * This is done in the following manner:
77  * - A linked list keeps track of locks held by a thread.
78  * - A `next' pointer is added to each lock. This is used to chain the locks together.
79  * - When taking a lock, the `add_lock_to_log_and_check' makes sure that taking
80  *   the given lock is legal. It will follow the linked list  to find the last
81  *   lock taken by this thread. If the last lock's order was lower than the
82  *   lock that is to be taken, it appends the new lock to the list and returns
83  *   true, if not, it return false. This return value is assert()'ed on in
84  *   _mali_osk_lock_wait().
85  */
86
87 static struct _mali_osk_lock_debug_s *lock_lookup_list;
88
89 static void dump_lock_tracking_list(void)
90 {
91         struct _mali_osk_lock_debug_s *l;
92         u32 n = 1;
93
94         /* print list for debugging purposes */
95         l = lock_lookup_list;
96
97         while (NULL != l) {
98                 printk(" [lock: %p, tid_owner: %d, order: %d] ->", l, l->owner, l->order);
99                 l = l->next;
100                 MALI_DEBUG_ASSERT(n++ < 100);
101         }
102         printk(" NULL\n");
103 }
104
105 static int tracking_list_length(void)
106 {
107         struct _mali_osk_lock_debug_s *l;
108         u32 n = 0;
109         l = lock_lookup_list;
110
111         while (NULL != l) {
112                 l = l->next;
113                 n++;
114                 MALI_DEBUG_ASSERT(n < 100);
115         }
116         return n;
117 }
118
119 static mali_bool add_lock_to_log_and_check(struct _mali_osk_lock_debug_s *lock, uint32_t tid)
120 {
121         mali_bool ret = MALI_FALSE;
122         _mali_osk_lock_order_t highest_order_for_tid = _MALI_OSK_LOCK_ORDER_FIRST;
123         struct _mali_osk_lock_debug_s *highest_order_lock = (struct _mali_osk_lock_debug_s *)0xbeefbabe;
124         struct _mali_osk_lock_debug_s *l;
125         unsigned long local_lock_flag;
126         u32 len;
127
128         spin_lock_irqsave(&lock_tracking_lock, local_lock_flag);
129         len = tracking_list_length();
130
131         l  = lock_lookup_list;
132         if (NULL == l) { /* This is the first lock taken by this thread -- record and return true */
133                 lock_lookup_list = lock;
134                 spin_unlock_irqrestore(&lock_tracking_lock, local_lock_flag);
135                 return MALI_TRUE;
136         } else {
137                 /* Traverse the locks taken and find the lock of the highest order.
138                  * Since several threads may hold locks, each lock's owner must be
139                  * checked so that locks not owned by this thread can be ignored. */
140                 for (;;) {
141                         MALI_DEBUG_ASSERT_POINTER(l);
142                         if (tid == l->owner && l->order >= highest_order_for_tid) {
143                                 highest_order_for_tid = l->order;
144                                 highest_order_lock = l;
145                         }
146
147                         if (NULL != l->next) {
148                                 l = l->next;
149                         } else {
150                                 break;
151                         }
152                 }
153
154                 l->next = lock;
155                 l->next = NULL;
156         }
157
158         /* We have now found the highest order lock currently held by this thread and can see if it is
159          * legal to take the requested lock. */
160         ret = highest_order_for_tid < lock->order;
161
162         if (!ret) {
163                 printk(KERN_ERR "Took lock of order %d (%s) while holding lock of order %d (%s)\n",
164                        lock->order, lock_order_to_string(lock->order),
165                        highest_order_for_tid, lock_order_to_string(highest_order_for_tid));
166                 dump_lock_tracking_list();
167         }
168
169         if (len + 1 != tracking_list_length()) {
170                 printk(KERN_ERR "************ lock: %p\n", lock);
171                 printk(KERN_ERR "************ before: %d *** after: %d ****\n", len, tracking_list_length());
172                 dump_lock_tracking_list();
173                 MALI_DEBUG_ASSERT_POINTER(NULL);
174         }
175
176         spin_unlock_irqrestore(&lock_tracking_lock, local_lock_flag);
177         return ret;
178 }
179
180 static void remove_lock_from_log(struct _mali_osk_lock_debug_s *lock, uint32_t tid)
181 {
182         struct _mali_osk_lock_debug_s *curr;
183         struct _mali_osk_lock_debug_s *prev = NULL;
184         unsigned long local_lock_flag;
185         u32 len;
186         u32 n = 0;
187
188         spin_lock_irqsave(&lock_tracking_lock, local_lock_flag);
189         len = tracking_list_length();
190         curr = lock_lookup_list;
191
192         if (NULL == curr) {
193                 printk(KERN_ERR "Error: Lock tracking list was empty on call to remove_lock_from_log\n");
194                 dump_lock_tracking_list();
195         }
196
197         MALI_DEBUG_ASSERT_POINTER(curr);
198
199
200         while (lock != curr) {
201                 prev = curr;
202
203                 MALI_DEBUG_ASSERT_POINTER(curr);
204                 curr = curr->next;
205                 MALI_DEBUG_ASSERT(n++ < 100);
206         }
207
208         if (NULL == prev) {
209                 lock_lookup_list = curr->next;
210         } else {
211                 MALI_DEBUG_ASSERT_POINTER(curr);
212                 MALI_DEBUG_ASSERT_POINTER(prev);
213                 prev->next = curr->next;
214         }
215
216         lock->next = NULL;
217
218         if (len - 1 != tracking_list_length()) {
219                 printk(KERN_ERR "************ lock: %p\n", lock);
220                 printk(KERN_ERR "************ before: %d *** after: %d ****\n", len, tracking_list_length());
221                 dump_lock_tracking_list();
222                 MALI_DEBUG_ASSERT_POINTER(NULL);
223         }
224
225         spin_unlock_irqrestore(&lock_tracking_lock, local_lock_flag);
226 }
227
228 static const char *const lock_order_to_string(_mali_osk_lock_order_t order)
229 {
230         switch (order) {
231         case _MALI_OSK_LOCK_ORDER_SESSIONS:
232                 return "_MALI_OSK_LOCK_ORDER_SESSIONS";
233                 break;
234         case _MALI_OSK_LOCK_ORDER_MEM_SESSION:
235                 return "_MALI_OSK_LOCK_ORDER_MEM_SESSION";
236                 break;
237         case _MALI_OSK_LOCK_ORDER_MEM_INFO:
238                 return "_MALI_OSK_LOCK_ORDER_MEM_INFO";
239                 break;
240         case _MALI_OSK_LOCK_ORDER_MEM_PT_CACHE:
241                 return "_MALI_OSK_LOCK_ORDER_MEM_PT_CACHE";
242                 break;
243         case _MALI_OSK_LOCK_ORDER_DESCRIPTOR_MAP:
244                 return "_MALI_OSK_LOCK_ORDER_DESCRIPTOR_MAP";
245                 break;
246         case _MALI_OSK_LOCK_ORDER_PM_EXECUTION:
247                 return "_MALI_OSK_LOCK_ORDER_PM_EXECUTION";
248                 break;
249         case _MALI_OSK_LOCK_ORDER_EXECUTOR:
250                 return "_MALI_OSK_LOCK_ORDER_EXECUTOR";
251                 break;
252         case _MALI_OSK_LOCK_ORDER_TIMELINE_SYSTEM:
253                 return "_MALI_OSK_LOCK_ORDER_TIMELINE_SYSTEM";
254                 break;
255         case _MALI_OSK_LOCK_ORDER_SCHEDULER:
256                 return "_MALI_OSK_LOCK_ORDER_SCHEDULER";
257                 break;
258         case _MALI_OSK_LOCK_ORDER_SCHEDULER_DEFERRED:
259                 return "_MALI_OSK_LOCK_ORDER_SCHEDULER_DEFERRED";
260                 break;
261         case _MALI_OSK_LOCK_ORDER_DMA_COMMAND:
262                 return "_MALI_OSK_LOCK_ORDER_DMA_COMMAND";
263                 break;
264         case _MALI_OSK_LOCK_ORDER_PROFILING:
265                 return "_MALI_OSK_LOCK_ORDER_PROFILING";
266                 break;
267         case _MALI_OSK_LOCK_ORDER_L2:
268                 return "_MALI_OSK_LOCK_ORDER_L2";
269                 break;
270         case _MALI_OSK_LOCK_ORDER_L2_COMMAND:
271                 return "_MALI_OSK_LOCK_ORDER_L2_COMMAND";
272                 break;
273         case _MALI_OSK_LOCK_ORDER_UTILIZATION:
274                 return "_MALI_OSK_LOCK_ORDER_UTILIZATION";
275                 break;
276         case _MALI_OSK_LOCK_ORDER_SESSION_PENDING_JOBS:
277                 return "_MALI_OSK_LOCK_ORDER_SESSION_PENDING_JOBS";
278                 break;
279         case _MALI_OSK_LOCK_ORDER_PM_STATE:
280                 return "_MALI_OSK_LOCK_ORDER_PM_STATE";
281                 break;
282         default:
283                 return "<UNKNOWN_LOCK_ORDER>";
284         }
285 }
286 #endif /* LOCK_ORDER_CHECKING */
287 #endif /* DEBUG */