2 * Copyright (C) 2010 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.c
13 * Implemenation of the OS abstraction layer for the kernel device driver
16 /* needed to detect kernel version specific code */
17 #include <linux/version.h>
19 #include <linux/spinlock.h>
20 #include <linux/rwsem.h>
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>
28 #include <linux/slab.h>
30 #include "mali_kernel_common.h"
32 /* These are all the locks we implement: */
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}() */
41 /* Linux supports, but we do not support:
42 * Non-Interruptable Reader/Writer spinlock mutexes - RW optimization will be switched off
45 /* Linux does not support:
46 * One-locks, of any sort - no optimization for this fact will be made.
49 } _mali_osk_internal_locktype;
51 struct _mali_osk_lock_t_struct
53 _mali_osk_internal_locktype type;
58 struct semaphore sema;
59 struct rw_semaphore rw_sema;
62 /** original flags for debug checking */
63 _mali_osk_lock_flags_t orig_flags;
64 ); /* MALI_DEBUG_CODE */
67 _mali_osk_lock_t *_mali_osk_lock_init( _mali_osk_lock_flags_t flags, u32 initial, u32 order )
69 _mali_osk_lock_t *lock = NULL;
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 );
85 lock = kmalloc(sizeof(_mali_osk_lock_t), GFP_KERNEL);
92 /* Determine type of mutex: */
93 /* defaults to interruptable mutex if no flags are specified */
95 if ( (flags & _MALI_OSK_LOCKFLAG_SPINLOCK) )
97 /* Non-interruptable Spinlocks override all others */
98 lock->type = _MALI_OSK_INTERNAL_LOCKTYPE_SPIN;
99 spin_lock_init( &lock->obj.spinlock );
101 else if ( (flags & _MALI_OSK_LOCKFLAG_SPINLOCK_IRQ ) )
103 lock->type = _MALI_OSK_INTERNAL_LOCKTYPE_SPIN_IRQ;
105 spin_lock_init( &lock->obj.spinlock );
107 else if ( (flags & _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE)
108 && (flags & _MALI_OSK_LOCKFLAG_READERWRITER) )
110 lock->type = _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT_RW;
111 init_rwsem( &lock->obj.rw_sema );
115 /* Usual mutex types */
116 if ( (flags & _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE) )
118 lock->type = _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT;
122 lock->type = _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX;
125 /* Initially unlocked */
126 sema_init( &lock->obj.sema, 1 );
130 /* Debug tracking of flags */
131 lock->orig_flags = flags;
132 ); /* MALI_DEBUG_CODE */
137 _mali_osk_errcode_t _mali_osk_lock_wait( _mali_osk_lock_t *lock, _mali_osk_lock_mode_t mode)
139 _mali_osk_errcode_t err = _MALI_OSK_ERR_OK;
141 /* Parameter validation */
142 MALI_DEBUG_ASSERT_POINTER( lock );
144 MALI_DEBUG_ASSERT( _MALI_OSK_LOCKMODE_RW == mode
145 || _MALI_OSK_LOCKMODE_RO == mode );
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)) );
153 switch ( lock->type )
155 case _MALI_OSK_INTERNAL_LOCKTYPE_SPIN:
156 spin_lock(&lock->obj.spinlock);
158 case _MALI_OSK_INTERNAL_LOCKTYPE_SPIN_IRQ:
159 spin_lock_irqsave(&lock->obj.spinlock, lock->flags);
162 case _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX:
163 if ( down_interruptible(&lock->obj.sema) )
165 err = _MALI_OSK_ERR_RESTARTSYSCALL;
169 case _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT:
170 down(&lock->obj.sema);
173 case _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT_RW:
174 if (mode == _MALI_OSK_LOCKMODE_RO)
176 down_read(&lock->obj.rw_sema);
180 down_write(&lock->obj.rw_sema);
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 ) );
194 void _mali_osk_lock_signal( _mali_osk_lock_t *lock, _mali_osk_lock_mode_t mode )
196 /* Parameter validation */
197 MALI_DEBUG_ASSERT_POINTER( lock );
199 MALI_DEBUG_ASSERT( _MALI_OSK_LOCKMODE_RW == mode
200 || _MALI_OSK_LOCKMODE_RO == mode );
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)) );
208 switch ( lock->type )
210 case _MALI_OSK_INTERNAL_LOCKTYPE_SPIN:
211 spin_unlock(&lock->obj.spinlock);
213 case _MALI_OSK_INTERNAL_LOCKTYPE_SPIN_IRQ:
214 spin_unlock_irqrestore(&lock->obj.spinlock, lock->flags);
217 case _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX:
219 case _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT:
223 case _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX_NONINT_RW:
224 if (mode == _MALI_OSK_LOCKMODE_RO)
226 up_read(&lock->obj.rw_sema);
230 up_write(&lock->obj.rw_sema);
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 ) );
242 void _mali_osk_lock_term( _mali_osk_lock_t *lock )
244 /* Parameter validation */
245 MALI_DEBUG_ASSERT_POINTER( lock );
247 /* Linux requires no explicit termination of spinlocks, semaphores, or rw_semaphores */