tizen 2.4 release
[kernel/linux-3.0.git] / drivers / gpu / arm / mali400 / r4p0_rel0 / linux / mali_osk_locks.h
1 /*
2  * Copyright (C) 2010-2012 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.h
13  * Defines OS abstraction of lock and mutex
14  */
15 #ifndef _MALI_OSK_LOCKS_H
16 #define _MALI_OSK_LOCKS_H
17
18 #include <linux/spinlock.h>
19 #include <linux/rwsem.h>
20 #include <linux/mutex.h>
21
22 #include <linux/slab.h>
23
24 #include "mali_osk_types.h"
25
26 #ifdef _cplusplus
27 extern "C" {
28 #endif
29
30         /* When DEBUG is enabled, this struct will be used to track owner, mode and order checking */
31 #ifdef DEBUG
32         struct _mali_osk_lock_debug_s {
33                 u32 owner;
34                 _mali_osk_lock_flags_t orig_flags;
35                 _mali_osk_lock_order_t order;
36                 struct _mali_osk_lock_debug_s *next;
37         };
38 #endif
39
40         /* Anstraction of spinlock_t */
41         struct _mali_osk_spinlock_s {
42 #ifdef DEBUG
43                 struct _mali_osk_lock_debug_s checker;
44 #endif
45                 spinlock_t spinlock;
46         };
47
48         /* Abstration of spinlock_t and lock flag which is used to store register's state before locking */
49         struct _mali_osk_spinlock_irq_s {
50 #ifdef DEBUG
51                 struct _mali_osk_lock_debug_s checker;
52 #endif
53
54                 spinlock_t spinlock;
55                 unsigned long flags;
56         };
57
58         /* Abstraction of rw_semaphore in OS */
59         struct _mali_osk_mutex_rw_s {
60 #ifdef DEBUG
61                 struct _mali_osk_lock_debug_s checker;
62                 _mali_osk_lock_mode_t mode;
63 #endif
64
65                 struct rw_semaphore rw_sema;
66         };
67
68         /* Mutex and mutex_interruptible functions share the same osk mutex struct */
69         struct _mali_osk_mutex_s {
70 #ifdef DEBUG
71                 struct _mali_osk_lock_debug_s checker;
72 #endif
73                 struct mutex mutex;
74         };
75
76 #ifdef DEBUG
77         /** @brief _mali_osk_locks_debug_init/add/remove() functions are declared when DEBUG is enabled and
78          * defined in file mali_osk_locks.c. When LOCK_ORDER_CHECKING is enabled, calling these functions when we
79          * init/lock/unlock a lock/mutex, we could track lock order of a given tid. */
80         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);
81         void _mali_osk_locks_debug_add(struct _mali_osk_lock_debug_s *checker);
82         void _mali_osk_locks_debug_remove(struct _mali_osk_lock_debug_s *checker);
83
84         /** @brief This function can return a given lock's owner when DEBUG     is enabled. */
85         static inline u32 _mali_osk_lock_get_owner(struct _mali_osk_lock_debug_s *lock)
86         {
87                 return lock->owner;
88         }
89 #else
90 #define _mali_osk_locks_debug_init(x, y, z) do {} while (0)
91 #define _mali_osk_locks_debug_add(x) do {} while (0)
92 #define _mali_osk_locks_debug_remove(x) do {} while (0)
93 #endif
94
95         /** @brief Before use _mali_osk_spin_lock, init function should be used to allocate memory and initial spinlock*/
96         static inline _mali_osk_spinlock_t *_mali_osk_spinlock_init(_mali_osk_lock_flags_t flags, _mali_osk_lock_order_t order)
97         {
98                 _mali_osk_spinlock_t *lock = NULL;
99
100                 lock = kmalloc(sizeof(_mali_osk_spinlock_t), GFP_KERNEL);
101                 if (NULL == lock) {
102                         return NULL;
103                 }
104                 spin_lock_init(&lock->spinlock);
105                 _mali_osk_locks_debug_init((struct _mali_osk_lock_debug_s *)lock, flags, order);
106                 return lock;
107         }
108
109         /** @brief Lock a spinlock */
110         static inline void  _mali_osk_spinlock_lock(_mali_osk_spinlock_t *lock)
111         {
112                 BUG_ON(NULL == lock);
113                 spin_lock(&lock->spinlock);
114                 _mali_osk_locks_debug_add((struct _mali_osk_lock_debug_s *)lock);
115         }
116
117         /** @brief Unlock a spinlock */
118         static inline void _mali_osk_spinlock_unlock(_mali_osk_spinlock_t *lock)
119         {
120                 BUG_ON(NULL == lock);
121                 _mali_osk_locks_debug_remove((struct _mali_osk_lock_debug_s *)lock);
122                 spin_unlock(&lock->spinlock);
123         }
124
125         /** @brief Free a memory block which the argument lock pointed to and its type must be
126          * _mali_osk_spinlock_t *. */
127         static inline void _mali_osk_spinlock_term(_mali_osk_spinlock_t *lock)
128         {
129                 /* Parameter validation  */
130                 BUG_ON(NULL == lock);
131
132                 /* Linux requires no explicit termination of spinlocks, semaphores, or rw_semaphores */
133                 kfree(lock);
134         }
135
136         /** @brief Before _mali_osk_spinlock_irq_lock/unlock/term() is called, init function should be
137          * called to initial spinlock and flags in struct _mali_osk_spinlock_irq_t. */
138         static inline _mali_osk_spinlock_irq_t *_mali_osk_spinlock_irq_init(_mali_osk_lock_flags_t flags, _mali_osk_lock_order_t order)
139         {
140                 _mali_osk_spinlock_irq_t *lock = NULL;
141                 lock = kmalloc(sizeof(_mali_osk_spinlock_irq_t), GFP_KERNEL);
142
143                 if (NULL == lock) {
144                         return NULL;
145                 }
146
147                 lock->flags = 0;
148                 spin_lock_init(&lock->spinlock);
149                 _mali_osk_locks_debug_init((struct _mali_osk_lock_debug_s *)lock, flags, order);
150                 return lock;
151         }
152
153         /** @brief Lock spinlock and save the register's state */
154         static inline void _mali_osk_spinlock_irq_lock(_mali_osk_spinlock_irq_t *lock)
155         {
156                 unsigned long tmp_flags;
157
158                 BUG_ON(NULL == lock);
159                 spin_lock_irqsave(&lock->spinlock, tmp_flags);
160                 lock->flags = tmp_flags;
161                 _mali_osk_locks_debug_add((struct _mali_osk_lock_debug_s *)lock);
162         }
163
164         /** @brief Unlock spinlock with saved register's state */
165         static inline void _mali_osk_spinlock_irq_unlock(_mali_osk_spinlock_irq_t *lock)
166         {
167                 BUG_ON(NULL == lock);
168                 _mali_osk_locks_debug_remove((struct _mali_osk_lock_debug_s *)lock);
169                 spin_unlock_irqrestore(&lock->spinlock, lock->flags);
170         }
171
172         /** @brief Destroy a given memory block which lock pointed to, and the lock type must be
173          * _mali_osk_spinlock_irq_t *. */
174         static inline void _mali_osk_spinlock_irq_term(_mali_osk_spinlock_irq_t *lock)
175         {
176                 /* Parameter validation  */
177                 BUG_ON(NULL == lock);
178
179                 /* Linux requires no explicit termination of spinlocks, semaphores, or rw_semaphores */
180                 kfree(lock);
181         }
182
183         /** @brief Before _mali_osk_mutex_rw_wait/signal/term() is called, we should call
184          * _mali_osk_mutex_rw_init() to kmalloc a memory block and initial part of elements in it. */
185         static inline _mali_osk_mutex_rw_t *_mali_osk_mutex_rw_init(_mali_osk_lock_flags_t flags, _mali_osk_lock_order_t order)
186         {
187                 _mali_osk_mutex_rw_t *lock = NULL;
188
189                 lock = kmalloc(sizeof(_mali_osk_mutex_rw_t), GFP_KERNEL);
190
191                 if (NULL == lock) {
192                         return NULL;
193                 }
194
195                 init_rwsem(&lock->rw_sema);
196                 _mali_osk_locks_debug_init((struct _mali_osk_lock_debug_s *)lock, flags, order);
197                 return lock;
198         }
199
200         /** @brief When call _mali_osk_mutex_rw_wait/signal() functions, the second argument mode
201          * should be assigned with value _MALI_OSK_LOCKMODE_RO or _MALI_OSK_LOCKMODE_RW */
202         static inline void _mali_osk_mutex_rw_wait(_mali_osk_mutex_rw_t *lock, _mali_osk_lock_mode_t mode)
203         {
204                 BUG_ON(NULL == lock);
205                 BUG_ON(!(_MALI_OSK_LOCKMODE_RO == mode || _MALI_OSK_LOCKMODE_RW == mode));
206
207                 if (mode == _MALI_OSK_LOCKMODE_RO) {
208                         down_read(&lock->rw_sema);
209                 } else {
210                         down_write(&lock->rw_sema);
211                 }
212
213 #ifdef DEBUG
214                 if (mode == _MALI_OSK_LOCKMODE_RW) {
215                         lock->mode = mode;
216                 } else { /* mode == _MALI_OSK_LOCKMODE_RO */
217                         lock->mode = mode;
218                 }
219                 _mali_osk_locks_debug_add((struct _mali_osk_lock_debug_s *)lock);
220 #endif
221         }
222
223         /** @brief Up lock->rw_sema with up_read/write() accordinf argument mode's value. */
224         static inline void  _mali_osk_mutex_rw_signal(_mali_osk_mutex_rw_t *lock, _mali_osk_lock_mode_t mode)
225         {
226                 BUG_ON(NULL == lock);
227                 BUG_ON(!(_MALI_OSK_LOCKMODE_RO == mode || _MALI_OSK_LOCKMODE_RW == mode));
228 #ifdef DEBUG
229                 /* make sure the thread releasing the lock actually was the owner */
230                 if (mode == _MALI_OSK_LOCKMODE_RW) {
231                         _mali_osk_locks_debug_remove((struct _mali_osk_lock_debug_s *)lock);
232                         /* This lock now has no owner */
233                         lock->checker.owner = 0;
234                 }
235 #endif
236
237                 if (mode == _MALI_OSK_LOCKMODE_RO) {
238                         up_read(&lock->rw_sema);
239                 } else {
240                         up_write(&lock->rw_sema);
241                 }
242         }
243
244         /** @brief Free a given memory block which lock pointed to and its type must be
245          * _mali_sok_mutex_rw_t *. */
246         static inline void _mali_osk_mutex_rw_term(_mali_osk_mutex_rw_t *lock)
247         {
248                 /* Parameter validation  */
249                 BUG_ON(NULL == lock);
250
251                 /* Linux requires no explicit termination of spinlocks, semaphores, or rw_semaphores */
252                 kfree(lock);
253         }
254
255         /** @brief Mutex & mutex_interruptible share the same init and term function, because they have the
256          * same osk mutex struct, and the difference between them is which locking function they use */
257         static inline _mali_osk_mutex_t *_mali_osk_mutex_init(_mali_osk_lock_flags_t flags, _mali_osk_lock_order_t order)
258         {
259                 _mali_osk_mutex_t *lock = NULL;
260
261                 lock = kmalloc(sizeof(_mali_osk_mutex_t), GFP_KERNEL);
262
263                 if (NULL == lock) {
264                         return NULL;
265                 }
266                 mutex_init(&lock->mutex);
267
268                 _mali_osk_locks_debug_init((struct _mali_osk_lock_debug_s *)lock, flags, order);
269                 return lock;
270         }
271
272         /** @brief  Lock the lock->mutex with mutex_lock_interruptible function */
273         static inline _mali_osk_errcode_t _mali_osk_mutex_wait_interruptible(_mali_osk_mutex_t *lock)
274         {
275                 _mali_osk_errcode_t err = _MALI_OSK_ERR_OK;
276
277                 BUG_ON(NULL == lock);
278
279                 if (mutex_lock_interruptible(&lock->mutex)) {
280                         printk(KERN_WARNING "Mali: Can not lock mutex\n");
281                         err = _MALI_OSK_ERR_RESTARTSYSCALL;
282                 }
283
284                 _mali_osk_locks_debug_add((struct _mali_osk_lock_debug_s *)lock);
285                 return err;
286         }
287
288         /** @brief Unlock the lock->mutex which is locked with mutex_lock_interruptible() function. */
289         static inline void _mali_osk_mutex_signal_interruptible(_mali_osk_mutex_t *lock)
290         {
291                 BUG_ON(NULL == lock);
292                 _mali_osk_locks_debug_remove((struct _mali_osk_lock_debug_s *)lock);
293                 mutex_unlock(&lock->mutex);
294         }
295
296         /** @brief Lock the lock->mutex just with mutex_lock() function which could not be interruptted. */
297         static inline void _mali_osk_mutex_wait(_mali_osk_mutex_t *lock)
298         {
299                 BUG_ON(NULL == lock);
300                 mutex_lock(&lock->mutex);
301                 _mali_osk_locks_debug_add((struct _mali_osk_lock_debug_s *)lock);
302         }
303
304         /** @brief Unlock the lock->mutex which is locked with mutex_lock() function. */
305         static inline void _mali_osk_mutex_signal(_mali_osk_mutex_t *lock)
306         {
307                 BUG_ON(NULL == lock);
308                 _mali_osk_locks_debug_remove((struct _mali_osk_lock_debug_s *)lock);
309                 mutex_unlock(&lock->mutex);
310         }
311
312         /** @brief Free a given memory block which lock point. */
313         static inline void _mali_osk_mutex_term(_mali_osk_mutex_t *lock)
314         {
315                 /* Parameter validation  */
316                 BUG_ON(NULL == lock);
317
318                 /* Linux requires no explicit termination of spinlocks, semaphores, or rw_semaphores */
319                 kfree(lock);
320         }
321
322 #ifdef _cplusplus
323 }
324 #endif
325
326 #endif