2005-04-16 15:20:36 -07:00
# ifndef _ASM_M32R_SEMAPHORE_H
# define _ASM_M32R_SEMAPHORE_H
# include <linux/linkage.h>
# ifdef __KERNEL__
/*
* SMP - and interrupt - safe semaphores . .
*
* Copyright ( C ) 1996 Linus Torvalds
2006-04-18 22:21:25 -07:00
* Copyright ( C ) 2004 , 2006 Hirokazu Takata < takata at linux - m32r . org >
2005-04-16 15:20:36 -07:00
*/
# include <linux/wait.h>
# include <linux/rwsem.h>
# include <asm/assembler.h>
# include <asm/system.h>
# include <asm/atomic.h>
struct semaphore {
atomic_t count ;
int sleepers ;
wait_queue_head_t wait ;
} ;
# define __SEMAPHORE_INITIALIZER(name, n) \
{ \
. count = ATOMIC_INIT ( n ) , \
. sleepers = 0 , \
. wait = __WAIT_QUEUE_HEAD_INITIALIZER ( ( name ) . wait ) \
}
# define __DECLARE_SEMAPHORE_GENERIC(name,count) \
struct semaphore name = __SEMAPHORE_INITIALIZER ( name , count )
# define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
# define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
static inline void sema_init ( struct semaphore * sem , int val )
{
/*
* * sem = ( struct semaphore ) __SEMAPHORE_INITIALIZER ( ( * sem ) , val ) ;
*
* i ' d rather use the more flexible initialization above , but sadly
* GCC 2.7 .2 .3 emits a bogus warning . EGCS doesnt . Oh well .
*/
atomic_set ( & sem - > count , val ) ;
sem - > sleepers = 0 ;
init_waitqueue_head ( & sem - > wait ) ;
}
static inline void init_MUTEX ( struct semaphore * sem )
{
sema_init ( sem , 1 ) ;
}
static inline void init_MUTEX_LOCKED ( struct semaphore * sem )
{
sema_init ( sem , 0 ) ;
}
asmlinkage void __down_failed ( void /* special register calling convention */ ) ;
asmlinkage int __down_failed_interruptible ( void /* params in registers */ ) ;
asmlinkage int __down_failed_trylock ( void /* params in registers */ ) ;
asmlinkage void __up_wakeup ( void /* special register calling convention */ ) ;
asmlinkage void __down ( struct semaphore * sem ) ;
asmlinkage int __down_interruptible ( struct semaphore * sem ) ;
asmlinkage int __down_trylock ( struct semaphore * sem ) ;
asmlinkage void __up ( struct semaphore * sem ) ;
/*
* Atomically decrement the semaphore ' s count . If it goes negative ,
* block the calling thread in the TASK_UNINTERRUPTIBLE state .
*/
static inline void down ( struct semaphore * sem )
{
might_sleep ( ) ;
2006-04-18 22:21:25 -07:00
if ( unlikely ( atomic_dec_return ( & sem - > count ) < 0 ) )
2005-04-16 15:20:36 -07:00
__down ( sem ) ;
}
/*
* Interruptible try to acquire a semaphore . If we obtained
* it , return zero . If we were interrupted , returns - EINTR
*/
static inline int down_interruptible ( struct semaphore * sem )
{
int result = 0 ;
might_sleep ( ) ;
2006-04-18 22:21:25 -07:00
if ( unlikely ( atomic_dec_return ( & sem - > count ) < 0 ) )
2005-04-16 15:20:36 -07:00
result = __down_interruptible ( sem ) ;
return result ;
}
/*
* Non - blockingly attempt to down ( ) a semaphore .
* Returns zero if we acquired it
*/
static inline int down_trylock ( struct semaphore * sem )
{
unsigned long flags ;
long count ;
int result = 0 ;
local_irq_save ( flags ) ;
__asm__ __volatile__ (
" # down_trylock \n \t "
DCACHE_CLEAR ( " %0 " , " r4 " , " %1 " )
M32R_LOCK " %0, @%1; \n \t "
" addi %0, #-1; \n \t "
M32R_UNLOCK " %0, @%1; \n \t "
: " =&r " ( count )
: " r " ( & sem - > count )
: " memory "
# ifdef CONFIG_CHIP_M32700_TS1
, " r4 "
# endif /* CONFIG_CHIP_M32700_TS1 */
) ;
local_irq_restore ( flags ) ;
if ( unlikely ( count < 0 ) )
result = __down_trylock ( sem ) ;
return result ;
}
/*
* Note ! This is subtle . We jump to wake people up only if
* the semaphore was negative ( = = somebody was waiting on it ) .
* The default case ( no contention ) will result in NO
* jumps for both down ( ) and up ( ) .
*/
static inline void up ( struct semaphore * sem )
{
2006-04-18 22:21:25 -07:00
if ( unlikely ( atomic_inc_return ( & sem - > count ) < = 0 ) )
2005-04-16 15:20:36 -07:00
__up ( sem ) ;
}
# endif /* __KERNEL__ */
# endif /* _ASM_M32R_SEMAPHORE_H */