tizen 2.4 release
[kernel/linux-3.0.git] / drivers / gpu / arm / mali400 / mali / linux / mali_osk_locks.c
1 /*
2  * Copyright (C) 2011-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.c
13  * Implemenation of the OS abstraction layer for the kernel device driver
14  */
15
16 #include <linux/spinlock.h>
17 #include <linux/rwsem.h>
18 #include <linux/mutex.h>
19
20 #include <linux/slab.h>
21
22 #include "mali_osk.h"
23 #include "mali_kernel_common.h"
24
25 /* These are all the locks we implement: */
26 typedef enum
27 {
28         _MALI_OSK_INTERNAL_LOCKTYPE_SPIN,            /* Mutex, implicitly non-interruptable, use spin_lock/spin_unlock */
29         _MALI_OSK_INTERNAL_LOCKTYPE_SPIN_IRQ,        /* Mutex, IRQ version of spinlock, use spin_lock_irqsave/spin_unlock_irqrestore */
30         _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX,           /* Interruptable, use mutex_unlock()/down_interruptable() */
31         _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT,    /* Non-Interruptable, use mutex_unlock()/down() */
32         _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT_RW, /* Non-interruptable, Reader/Writer, use {mutex_unlock,down}{read,write}() */
33
34         /* Linux supports, but we do not support:
35          * Non-Interruptable Reader/Writer spinlock mutexes - RW optimization will be switched off
36          */
37
38         /* Linux does not support:
39          * One-locks, of any sort - no optimization for this fact will be made.
40          */
41
42 } _mali_osk_internal_locktype;
43
44 struct _mali_osk_lock_t_struct
45 {
46     _mali_osk_internal_locktype type;
47         unsigned long flags;
48     union
49     {
50         spinlock_t spinlock;
51         struct mutex mutex;
52         struct rw_semaphore rw_sema;
53     } obj;
54         MALI_DEBUG_CODE(
55                                   /** original flags for debug checking */
56                                   _mali_osk_lock_flags_t orig_flags;
57
58                                   /* id of the thread currently holding this lock, 0 if no
59                                    * threads hold it. */
60                                   u32 owner;
61                                   /* number of owners this lock currently has (can be > 1 if
62                                    * taken in R/O mode. */
63                                   u32 nOwners;
64                                   /* what mode the lock was taken in */
65                                   _mali_osk_lock_mode_t mode;
66         ); /* MALI_DEBUG_CODE */
67 };
68
69 _mali_osk_lock_t *_mali_osk_lock_init( _mali_osk_lock_flags_t flags, u32 initial, u32 order )
70 {
71     _mali_osk_lock_t *lock = NULL;
72
73         /* Validate parameters: */
74         /* Flags acceptable */
75         MALI_DEBUG_ASSERT( 0 == ( flags & ~(_MALI_OSK_LOCKFLAG_SPINLOCK
76                                       | _MALI_OSK_LOCKFLAG_SPINLOCK_IRQ
77                                       | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE
78                                       | _MALI_OSK_LOCKFLAG_READERWRITER
79                                       | _MALI_OSK_LOCKFLAG_ORDERED
80                                       | _MALI_OSK_LOCKFLAG_ONELOCK )) );
81         /* Spinlocks are always non-interruptable */
82         MALI_DEBUG_ASSERT( (((flags & _MALI_OSK_LOCKFLAG_SPINLOCK) || (flags & _MALI_OSK_LOCKFLAG_SPINLOCK_IRQ)) && (flags & _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE))
83                                          || !(flags & _MALI_OSK_LOCKFLAG_SPINLOCK));
84         /* Parameter initial SBZ - for future expansion */
85         MALI_DEBUG_ASSERT( 0 == initial );
86
87         lock = kmalloc(sizeof(_mali_osk_lock_t), GFP_KERNEL);
88
89         if ( NULL == lock )
90         {
91                 return lock;
92         }
93
94         /* Determine type of mutex: */
95     /* defaults to interruptable mutex if no flags are specified */
96
97         if ( (flags & _MALI_OSK_LOCKFLAG_SPINLOCK) )
98         {
99                 /* Non-interruptable Spinlocks override all others */
100                 lock->type = _MALI_OSK_INTERNAL_LOCKTYPE_SPIN;
101                 spin_lock_init( &lock->obj.spinlock );
102         }
103         else if ( (flags & _MALI_OSK_LOCKFLAG_SPINLOCK_IRQ ) )
104         {
105                 lock->type = _MALI_OSK_INTERNAL_LOCKTYPE_SPIN_IRQ;
106                 lock->flags = 0;
107                 spin_lock_init( &lock->obj.spinlock );
108         }
109         else if ( (flags & _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE)
110                           && (flags & _MALI_OSK_LOCKFLAG_READERWRITER) )
111         {
112                 lock->type = _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT_RW;
113                 init_rwsem( &lock->obj.rw_sema );
114         }
115         else
116         {
117                 /* Usual mutex types */
118                 if ( (flags & _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE) )
119                 {
120                         lock->type = _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT;
121                 }
122                 else
123                 {
124                         lock->type = _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX;
125                 }
126
127                 /* Initially unlocked */
128                 mutex_init(&lock->obj.mutex);
129         }
130
131 #ifdef DEBUG
132         /* Debug tracking of flags */
133         lock->orig_flags = flags;
134
135         /* Debug tracking of lock owner */
136         lock->owner = 0;
137         lock->nOwners = 0;
138 #endif /* DEBUG */
139
140     return lock;
141 }
142
143 #ifdef DEBUG
144 u32 _mali_osk_lock_get_owner( _mali_osk_lock_t *lock )
145 {
146         return lock->owner;
147 }
148
149 u32 _mali_osk_lock_get_number_owners( _mali_osk_lock_t *lock )
150 {
151         return lock->nOwners;
152 }
153
154 u32 _mali_osk_lock_get_mode( _mali_osk_lock_t *lock )
155 {
156         return lock->mode;
157 }
158 #endif /* DEBUG */
159
160 _mali_osk_errcode_t _mali_osk_lock_wait( _mali_osk_lock_t *lock, _mali_osk_lock_mode_t mode)
161 {
162     _mali_osk_errcode_t err = _MALI_OSK_ERR_OK;
163
164         /* Parameter validation */
165         MALI_DEBUG_ASSERT_POINTER( lock );
166
167         MALI_DEBUG_ASSERT( _MALI_OSK_LOCKMODE_RW == mode
168                                          || _MALI_OSK_LOCKMODE_RO == mode );
169
170         /* Only allow RO locks when the initial object was a Reader/Writer lock
171          * Since information is lost on the internal locktype, we use the original
172          * information, which is only stored when built for DEBUG */
173         MALI_DEBUG_ASSERT( _MALI_OSK_LOCKMODE_RW == mode
174                                          || (_MALI_OSK_LOCKMODE_RO == mode && (_MALI_OSK_LOCKFLAG_READERWRITER & lock->orig_flags)) );
175
176         switch ( lock->type )
177         {
178         case _MALI_OSK_INTERNAL_LOCKTYPE_SPIN:
179                 spin_lock(&lock->obj.spinlock);
180                 break;
181         case _MALI_OSK_INTERNAL_LOCKTYPE_SPIN_IRQ:
182                 {
183                         unsigned long tmp_flags;
184                         spin_lock_irqsave(&lock->obj.spinlock, tmp_flags);
185                         lock->flags = tmp_flags;
186                 }
187                 break;
188
189         case _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX:
190                 if (mutex_lock_interruptible(&lock->obj.mutex))
191                 {
192                         MALI_PRINT_ERROR(("Can not lock mutex\n"));
193                         err = _MALI_OSK_ERR_RESTARTSYSCALL;
194                 }
195                 break;
196
197         case _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT:
198                 mutex_lock(&lock->obj.mutex);
199                 break;
200
201         case _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT_RW:
202                 if (mode == _MALI_OSK_LOCKMODE_RO)
203         {
204             down_read(&lock->obj.rw_sema);
205         }
206         else
207         {
208             down_write(&lock->obj.rw_sema);
209         }
210                 break;
211
212         default:
213                 /* Reaching here indicates a programming error, so you will not get here
214                  * on non-DEBUG builds */
215                 MALI_DEBUG_PRINT_ERROR( ("Invalid internal lock type: %.8X", lock->type ) );
216                 break;
217         }
218
219 #ifdef DEBUG
220         /* This thread is now the owner of this lock */
221         if (_MALI_OSK_ERR_OK == err)
222         {
223                 if (mode == _MALI_OSK_LOCKMODE_RW)
224                 {
225                         /*MALI_DEBUG_ASSERT(0 == lock->owner);*/
226                         if (0 != lock->owner)
227                         {
228                                 printk(KERN_ERR "%d: ERROR: Lock %p already has owner %d\n", _mali_osk_get_tid(), lock, lock->owner);
229                                 dump_stack();
230                         }
231                         lock->owner = _mali_osk_get_tid();
232                         lock->mode = mode;
233                         ++lock->nOwners;
234                 }
235                 else /* mode == _MALI_OSK_LOCKMODE_RO */
236                 {
237                         lock->owner |= _mali_osk_get_tid();
238                         lock->mode = mode;
239                         ++lock->nOwners;
240                 }
241         }
242 #endif
243
244     return err;
245 }
246
247 void _mali_osk_lock_signal( _mali_osk_lock_t *lock, _mali_osk_lock_mode_t mode )
248 {
249         /* Parameter validation */
250         MALI_DEBUG_ASSERT_POINTER( lock );
251
252         MALI_DEBUG_ASSERT( _MALI_OSK_LOCKMODE_RW == mode
253                                          || _MALI_OSK_LOCKMODE_RO == mode );
254
255         /* Only allow RO locks when the initial object was a Reader/Writer lock
256          * Since information is lost on the internal locktype, we use the original
257          * information, which is only stored when built for DEBUG */
258         MALI_DEBUG_ASSERT( _MALI_OSK_LOCKMODE_RW == mode
259                                          || (_MALI_OSK_LOCKMODE_RO == mode && (_MALI_OSK_LOCKFLAG_READERWRITER & lock->orig_flags)) );
260
261 #ifdef DEBUG
262         /* make sure the thread releasing the lock actually was the owner */
263         if (mode == _MALI_OSK_LOCKMODE_RW)
264         {
265                 /*MALI_DEBUG_ASSERT(_mali_osk_get_tid() == lock->owner);*/
266                 if (_mali_osk_get_tid() != lock->owner)
267                 {
268                         printk(KERN_ERR "%d: ERROR: Lock %p owner was %d\n", _mali_osk_get_tid(), lock, lock->owner);
269                         dump_stack();
270                 }
271                 /* This lock now has no owner */
272                 lock->owner = 0;
273                 --lock->nOwners;
274         }
275         else /* mode == _MALI_OSK_LOCKMODE_RO */
276         {
277                 if ((_mali_osk_get_tid() & lock->owner) != _mali_osk_get_tid())
278                 {
279                         printk(KERN_ERR "%d: ERROR: Not an owner of %p lock.\n", _mali_osk_get_tid(), lock);
280                         dump_stack();
281                 }
282
283                 /* if this is the last thread holding this lock in R/O mode, set owner
284                  * back to 0 */
285                 if (0 == --lock->nOwners)
286                 {
287                         lock->owner = 0;
288                 }
289         }
290 #endif /* DEBUG */
291
292         switch ( lock->type )
293         {
294         case _MALI_OSK_INTERNAL_LOCKTYPE_SPIN:
295                 spin_unlock(&lock->obj.spinlock);
296                 break;
297         case _MALI_OSK_INTERNAL_LOCKTYPE_SPIN_IRQ:
298                 spin_unlock_irqrestore(&lock->obj.spinlock, lock->flags);
299                 break;
300
301         case _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX:
302                 /* FALLTHROUGH */
303         case _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT:
304                 mutex_unlock(&lock->obj.mutex);
305                 break;
306
307         case _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT_RW:
308                 if (mode == _MALI_OSK_LOCKMODE_RO)
309         {
310             up_read(&lock->obj.rw_sema);
311         }
312         else
313         {
314             up_write(&lock->obj.rw_sema);
315         }
316                 break;
317
318         default:
319                 /* Reaching here indicates a programming error, so you will not get here
320                  * on non-DEBUG builds */
321                 MALI_DEBUG_PRINT_ERROR( ("Invalid internal lock type: %.8X", lock->type ) );
322                 break;
323         }
324 }
325
326 void _mali_osk_lock_term( _mali_osk_lock_t *lock )
327 {
328         /* Parameter validation  */
329         MALI_DEBUG_ASSERT_POINTER( lock );
330
331         /* Linux requires no explicit termination of spinlocks, semaphores, or rw_semaphores */
332     kfree(lock);
333 }