2 * Copyright (C) 2010-2014 ARM Limited. All rights reserved.
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.
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.
12 * @file mali_osk_locks.h
13 * Defines OS abstraction of lock and mutex
15 #ifndef _MALI_OSK_LOCKS_H
16 #define _MALI_OSK_LOCKS_H
18 #include <linux/spinlock.h>
19 #include <linux/rwsem.h>
20 #include <linux/mutex.h>
22 #include <linux/slab.h>
24 #include "mali_osk_types.h"
30 /* When DEBUG is enabled, this struct will be used to track owner, mode and order checking */
32 struct _mali_osk_lock_debug_s {
34 _mali_osk_lock_flags_t orig_flags;
35 _mali_osk_lock_order_t order;
36 struct _mali_osk_lock_debug_s *next;
40 /* Anstraction of spinlock_t */
41 struct _mali_osk_spinlock_s {
43 struct _mali_osk_lock_debug_s checker;
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 {
51 struct _mali_osk_lock_debug_s checker;
58 /* Abstraction of rw_semaphore in OS */
59 struct _mali_osk_mutex_rw_s {
61 struct _mali_osk_lock_debug_s checker;
62 _mali_osk_lock_mode_t mode;
65 struct rw_semaphore rw_sema;
68 /* Mutex and mutex_interruptible functions share the same osk mutex struct */
69 struct _mali_osk_mutex_s {
71 struct _mali_osk_lock_debug_s checker;
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);
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)
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)
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)
98 _mali_osk_spinlock_t *lock = NULL;
100 lock = kmalloc(sizeof(_mali_osk_spinlock_t), GFP_KERNEL);
104 spin_lock_init(&lock->spinlock);
105 _mali_osk_locks_debug_init((struct _mali_osk_lock_debug_s *)lock, flags, order);
109 /** @brief Lock a spinlock */
110 static inline void _mali_osk_spinlock_lock(_mali_osk_spinlock_t *lock)
112 BUG_ON(NULL == lock);
113 spin_lock(&lock->spinlock);
114 _mali_osk_locks_debug_add((struct _mali_osk_lock_debug_s *)lock);
117 /** @brief Unlock a spinlock */
118 static inline void _mali_osk_spinlock_unlock(_mali_osk_spinlock_t *lock)
120 BUG_ON(NULL == lock);
121 _mali_osk_locks_debug_remove((struct _mali_osk_lock_debug_s *)lock);
122 spin_unlock(&lock->spinlock);
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)
129 /* Parameter validation */
130 BUG_ON(NULL == lock);
132 /* Linux requires no explicit termination of spinlocks, semaphores, or rw_semaphores */
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)
140 _mali_osk_spinlock_irq_t *lock = NULL;
141 lock = kmalloc(sizeof(_mali_osk_spinlock_irq_t), GFP_KERNEL);
148 spin_lock_init(&lock->spinlock);
149 _mali_osk_locks_debug_init((struct _mali_osk_lock_debug_s *)lock, flags, order);
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)
156 unsigned long tmp_flags;
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);
164 /** @brief Unlock spinlock with saved register's state */
165 static inline void _mali_osk_spinlock_irq_unlock(_mali_osk_spinlock_irq_t *lock)
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);
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)
176 /* Parameter validation */
177 BUG_ON(NULL == lock);
179 /* Linux requires no explicit termination of spinlocks, semaphores, or rw_semaphores */
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)
187 _mali_osk_mutex_rw_t *lock = NULL;
189 lock = kmalloc(sizeof(_mali_osk_mutex_rw_t), GFP_KERNEL);
195 init_rwsem(&lock->rw_sema);
196 _mali_osk_locks_debug_init((struct _mali_osk_lock_debug_s *)lock, flags, order);
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)
204 BUG_ON(NULL == lock);
205 BUG_ON(!(_MALI_OSK_LOCKMODE_RO == mode || _MALI_OSK_LOCKMODE_RW == mode));
207 if (mode == _MALI_OSK_LOCKMODE_RO) {
208 down_read(&lock->rw_sema);
210 down_write(&lock->rw_sema);
214 if (mode == _MALI_OSK_LOCKMODE_RW) {
216 } else { /* mode == _MALI_OSK_LOCKMODE_RO */
219 _mali_osk_locks_debug_add((struct _mali_osk_lock_debug_s *)lock);
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)
226 BUG_ON(NULL == lock);
227 BUG_ON(!(_MALI_OSK_LOCKMODE_RO == mode || _MALI_OSK_LOCKMODE_RW == mode));
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;
237 if (mode == _MALI_OSK_LOCKMODE_RO) {
238 up_read(&lock->rw_sema);
240 up_write(&lock->rw_sema);
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)
248 /* Parameter validation */
249 BUG_ON(NULL == lock);
251 /* Linux requires no explicit termination of spinlocks, semaphores, or rw_semaphores */
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)
259 _mali_osk_mutex_t *lock = NULL;
261 lock = kmalloc(sizeof(_mali_osk_mutex_t), GFP_KERNEL);
266 mutex_init(&lock->mutex);
268 _mali_osk_locks_debug_init((struct _mali_osk_lock_debug_s *)lock, flags, order);
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)
275 _mali_osk_errcode_t err = _MALI_OSK_ERR_OK;
277 BUG_ON(NULL == lock);
279 if (mutex_lock_interruptible(&lock->mutex)) {
280 printk(KERN_WARNING "Mali: Can not lock mutex\n");
281 err = _MALI_OSK_ERR_RESTARTSYSCALL;
284 _mali_osk_locks_debug_add((struct _mali_osk_lock_debug_s *)lock);
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)
291 BUG_ON(NULL == lock);
292 _mali_osk_locks_debug_remove((struct _mali_osk_lock_debug_s *)lock);
293 mutex_unlock(&lock->mutex);
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)
299 BUG_ON(NULL == lock);
300 mutex_lock(&lock->mutex);
301 _mali_osk_locks_debug_add((struct _mali_osk_lock_debug_s *)lock);
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)
307 BUG_ON(NULL == lock);
308 _mali_osk_locks_debug_remove((struct _mali_osk_lock_debug_s *)lock);
309 mutex_unlock(&lock->mutex);
312 /** @brief Free a given memory block which lock point. */
313 static inline void _mali_osk_mutex_term(_mali_osk_mutex_t *lock)
315 /* Parameter validation */
316 BUG_ON(NULL == lock);
318 /* Linux requires no explicit termination of spinlocks, semaphores, or rw_semaphores */