xref: /OK3568_Linux_fs/kernel/drivers/gpu/arm/mali400/mali/linux/mali_osk_locks.h (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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