1 /* 2 * Copyright (C) 2010-2014, 2016-2017 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. */ _mali_osk_lock_get_owner(struct _mali_osk_lock_debug_s * lock)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*/ _mali_osk_spinlock_init(_mali_osk_lock_flags_t flags,_mali_osk_lock_order_t order)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 */ _mali_osk_spinlock_lock(_mali_osk_spinlock_t * lock)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 */ _mali_osk_spinlock_unlock(_mali_osk_spinlock_t * lock)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 *. */ _mali_osk_spinlock_term(_mali_osk_spinlock_t * lock)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. */ _mali_osk_spinlock_irq_init(_mali_osk_lock_flags_t flags,_mali_osk_lock_order_t order)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 */ _mali_osk_spinlock_irq_lock(_mali_osk_spinlock_irq_t * lock)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 */ _mali_osk_spinlock_irq_unlock(_mali_osk_spinlock_irq_t * lock)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 *. */ _mali_osk_spinlock_irq_term(_mali_osk_spinlock_irq_t * lock)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. */ _mali_osk_mutex_rw_init(_mali_osk_lock_flags_t flags,_mali_osk_lock_order_t order)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 */ _mali_osk_mutex_rw_wait(_mali_osk_mutex_rw_t * lock,_mali_osk_lock_mode_t mode)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. */ _mali_osk_mutex_rw_signal(_mali_osk_mutex_rw_t * lock,_mali_osk_lock_mode_t mode)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 *. */ _mali_osk_mutex_rw_term(_mali_osk_mutex_rw_t * lock)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 */ _mali_osk_mutex_init(_mali_osk_lock_flags_t flags,_mali_osk_lock_order_t order)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 */ _mali_osk_mutex_wait_interruptible(_mali_osk_mutex_t * lock)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. */ _mali_osk_mutex_signal_interruptible(_mali_osk_mutex_t * lock)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. */ _mali_osk_mutex_wait(_mali_osk_mutex_t * lock)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. */ _mali_osk_mutex_signal(_mali_osk_mutex_t * lock)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. */ _mali_osk_mutex_term(_mali_osk_mutex_t * lock)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 327