upload tizen1.0 source
[kernel/linux-2.6.36.git] / drivers / media / video / samsung / mali / linux / mali_osk_locks.c
1 /*
2  * Copyright (C) 2010 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 /* needed to detect kernel version specific code */
17 #include <linux/version.h>
18
19 #include <linux/spinlock.h>
20 #include <linux/rwsem.h>
21
22 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
23 #include <linux/semaphore.h>
24 #else /* pre 2.6.26 the file was in the arch specific location */
25 #include <asm/semaphore.h>
26 #endif
27
28 #include <linux/slab.h>
29 #include "mali_osk.h"
30 #include "mali_kernel_common.h"
31
32 /* These are all the locks we implement: */
33 typedef enum
34 {
35         _MALI_OSK_INTERNAL_LOCKTYPE_SPIN,            /* Mutex, implicitly non-interruptable, use spin_lock/spin_unlock */
36         _MALI_OSK_INTERNAL_LOCKTYPE_SPIN_IRQ,        /* Mutex, IRQ version of spinlock, use spin_lock_irqsave/spin_unlock_irqrestore */
37         _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX,           /* Interruptable, use up()/down_interruptable() */
38         _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT,    /* Non-Interruptable, use up()/down() */
39         _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT_RW, /* Non-interruptable, Reader/Writer, use {up,down}{read,write}() */
40
41         /* Linux supports, but we do not support:
42          * Non-Interruptable Reader/Writer spinlock mutexes - RW optimization will be switched off
43          */
44
45         /* Linux does not support:
46          * One-locks, of any sort - no optimization for this fact will be made.
47          */
48
49 } _mali_osk_internal_locktype;
50
51 struct _mali_osk_lock_t_struct
52 {
53     _mali_osk_internal_locktype type;
54         unsigned long flags; 
55     union
56     {
57         spinlock_t spinlock;
58         struct semaphore sema;
59         struct rw_semaphore rw_sema;
60     } obj;
61         MALI_DEBUG_CODE(
62                                   /** original flags for debug checking */
63                                   _mali_osk_lock_flags_t orig_flags;
64         ); /* MALI_DEBUG_CODE */
65 };
66
67 _mali_osk_lock_t *_mali_osk_lock_init( _mali_osk_lock_flags_t flags, u32 initial, u32 order )
68 {
69     _mali_osk_lock_t *lock = NULL;
70
71         /* Validate parameters: */
72         /* Flags acceptable */
73         MALI_DEBUG_ASSERT( 0 == ( flags & ~(_MALI_OSK_LOCKFLAG_SPINLOCK
74                                                                           | _MALI_OSK_LOCKFLAG_SPINLOCK_IRQ
75                                                                           | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE
76                                                                           | _MALI_OSK_LOCKFLAG_READERWRITER
77                                                                           | _MALI_OSK_LOCKFLAG_ORDERED
78                                                                           | _MALI_OSK_LOCKFLAG_ONELOCK )) );
79         /* Spinlocks are always non-interruptable */
80         MALI_DEBUG_ASSERT( (((flags & _MALI_OSK_LOCKFLAG_SPINLOCK) || (flags & _MALI_OSK_LOCKFLAG_SPINLOCK_IRQ)) && (flags & _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE))
81                                          || !(flags & _MALI_OSK_LOCKFLAG_SPINLOCK));
82         /* Parameter initial SBZ - for future expansion */
83         MALI_DEBUG_ASSERT( 0 == initial );
84
85         lock = kmalloc(sizeof(_mali_osk_lock_t), GFP_KERNEL);
86
87         if ( NULL == lock )
88         {
89                 return lock;
90         }
91
92         /* Determine type of mutex: */
93     /* defaults to interruptable mutex if no flags are specified */
94
95         if ( (flags & _MALI_OSK_LOCKFLAG_SPINLOCK) )
96         {
97                 /* Non-interruptable Spinlocks override all others */
98                 lock->type = _MALI_OSK_INTERNAL_LOCKTYPE_SPIN;
99                 spin_lock_init( &lock->obj.spinlock );
100         }
101         else if ( (flags & _MALI_OSK_LOCKFLAG_SPINLOCK_IRQ ) )
102         {
103                 lock->type = _MALI_OSK_INTERNAL_LOCKTYPE_SPIN_IRQ;
104                 lock->flags = 0;
105                 spin_lock_init( &lock->obj.spinlock );
106         }
107         else if ( (flags & _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE)
108                           && (flags & _MALI_OSK_LOCKFLAG_READERWRITER) )
109         {
110                 lock->type = _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT_RW;
111                 init_rwsem( &lock->obj.rw_sema );
112         }
113         else
114         {
115                 /* Usual mutex types */
116                 if ( (flags & _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE) )
117                 {
118                         lock->type = _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT;
119                 }
120                 else
121                 {
122                         lock->type = _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX;
123                 }
124
125                 /* Initially unlocked */
126                 sema_init( &lock->obj.sema, 1 );
127         }
128
129         MALI_DEBUG_CODE(
130                                   /* Debug tracking of flags */
131                                   lock->orig_flags = flags;
132                                   ); /* MALI_DEBUG_CODE */
133
134     return lock;
135 }
136
137 _mali_osk_errcode_t _mali_osk_lock_wait( _mali_osk_lock_t *lock, _mali_osk_lock_mode_t mode)
138 {
139     _mali_osk_errcode_t err = _MALI_OSK_ERR_OK;
140
141         /* Parameter validation */
142         MALI_DEBUG_ASSERT_POINTER( lock );
143
144         MALI_DEBUG_ASSERT( _MALI_OSK_LOCKMODE_RW == mode
145                                          || _MALI_OSK_LOCKMODE_RO == mode );
146
147         /* Only allow RO locks when the initial object was a Reader/Writer lock
148          * Since information is lost on the internal locktype, we use the original
149          * information, which is only stored when built for DEBUG */
150         MALI_DEBUG_ASSERT( _MALI_OSK_LOCKMODE_RW == mode
151                                          || (_MALI_OSK_LOCKMODE_RO == mode && (_MALI_OSK_LOCKFLAG_READERWRITER & lock->orig_flags)) );
152
153         switch ( lock->type )
154         {
155         case _MALI_OSK_INTERNAL_LOCKTYPE_SPIN:
156                 spin_lock(&lock->obj.spinlock);
157                 break;
158         case _MALI_OSK_INTERNAL_LOCKTYPE_SPIN_IRQ:
159                 spin_lock_irqsave(&lock->obj.spinlock, lock->flags);
160                 break;
161
162         case _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX:
163                 if ( down_interruptible(&lock->obj.sema) )
164                 {
165                         err = _MALI_OSK_ERR_RESTARTSYSCALL;
166                 }
167                 break;
168
169         case _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT:
170                 down(&lock->obj.sema);
171                 break;
172
173         case _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT_RW:
174                 if (mode == _MALI_OSK_LOCKMODE_RO)
175         {
176             down_read(&lock->obj.rw_sema);
177         }
178         else
179         {
180             down_write(&lock->obj.rw_sema);
181         }
182                 break;
183
184         default:
185                 /* Reaching here indicates a programming error, so you will not get here
186                  * on non-DEBUG builds */
187                 MALI_DEBUG_PRINT_ERROR( ("Invalid internal lock type: %.8X", lock->type ) );
188                 break;
189         }
190
191     return err;
192 }
193
194 void _mali_osk_lock_signal( _mali_osk_lock_t *lock, _mali_osk_lock_mode_t mode )
195 {
196         /* Parameter validation */
197         MALI_DEBUG_ASSERT_POINTER( lock );
198
199         MALI_DEBUG_ASSERT( _MALI_OSK_LOCKMODE_RW == mode
200                                          || _MALI_OSK_LOCKMODE_RO == mode );
201
202         /* Only allow RO locks when the initial object was a Reader/Writer lock
203          * Since information is lost on the internal locktype, we use the original
204          * information, which is only stored when built for DEBUG */
205         MALI_DEBUG_ASSERT( _MALI_OSK_LOCKMODE_RW == mode
206                                          || (_MALI_OSK_LOCKMODE_RO == mode && (_MALI_OSK_LOCKFLAG_READERWRITER & lock->orig_flags)) );
207
208         switch ( lock->type )
209         {
210         case _MALI_OSK_INTERNAL_LOCKTYPE_SPIN:
211                 spin_unlock(&lock->obj.spinlock);
212                 break;
213         case _MALI_OSK_INTERNAL_LOCKTYPE_SPIN_IRQ:
214                 spin_unlock_irqrestore(&lock->obj.spinlock, lock->flags);
215                 break;
216
217         case _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX:
218                 /* FALLTHROUGH */
219         case _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT:
220                 up(&lock->obj.sema);
221                 break;
222
223         case _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT_RW:
224                 if (mode == _MALI_OSK_LOCKMODE_RO)
225         {
226             up_read(&lock->obj.rw_sema);
227         }
228         else
229         {
230             up_write(&lock->obj.rw_sema);
231         }
232                 break;
233
234         default:
235                 /* Reaching here indicates a programming error, so you will not get here
236                  * on non-DEBUG builds */
237                 MALI_DEBUG_PRINT_ERROR( ("Invalid internal lock type: %.8X", lock->type ) );
238                 break;
239         }
240 }
241
242 void _mali_osk_lock_term( _mali_osk_lock_t *lock )
243 {
244         /* Parameter validation  */
245         MALI_DEBUG_ASSERT_POINTER( lock );
246
247         /* Linux requires no explicit termination of spinlocks, semaphores, or rw_semaphores */
248     kfree(lock);
249 }