2009-05-14 02:56:35 +04:00
/*
* Generic C implementation of atomic counter operations
* Originally implemented for MN10300 .
*
* Copyright ( C ) 2007 Red Hat , Inc . All Rights Reserved .
* Written by David Howells ( dhowells @ redhat . com )
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation ; either version
* 2 of the Licence , or ( at your option ) any later version .
*/
# ifndef __ASM_GENERIC_ATOMIC_H
# define __ASM_GENERIC_ATOMIC_H
# ifdef CONFIG_SMP
# error not SMP safe
# endif
/*
* Atomic operations that C can ' t guarantee us . Useful for
* resource counting etc . .
*/
# define ATOMIC_INIT(i) { (i) }
# ifdef __KERNEL__
/**
* atomic_read - read atomic variable
* @ v : pointer of type atomic_t
*
2010-05-25 01:33:09 +04:00
* Atomically reads the value of @ v .
2009-05-14 02:56:35 +04:00
*/
2010-05-17 08:33:53 +04:00
# define atomic_read(v) (*(volatile int *)&(v)->counter)
2009-05-14 02:56:35 +04:00
/**
* atomic_set - set atomic variable
* @ v : pointer of type atomic_t
* @ i : required value
*
2010-05-25 01:33:09 +04:00
* Atomically sets the value of @ v to @ i .
2009-05-14 02:56:35 +04:00
*/
# define atomic_set(v, i) (((v)->counter) = (i))
# include <asm/system.h>
/**
* atomic_add_return - add integer to atomic variable
* @ i : integer value to add
* @ v : pointer of type atomic_t
*
* Atomically adds @ i to @ v and returns the result
*/
static inline int atomic_add_return ( int i , atomic_t * v )
{
unsigned long flags ;
int temp ;
2010-08-10 04:18:24 +04:00
raw_local_irq_save ( flags ) ; /* Don't trace it in a irqsoff handler */
2009-05-14 02:56:35 +04:00
temp = v - > counter ;
temp + = i ;
v - > counter = temp ;
2010-08-10 04:18:24 +04:00
raw_local_irq_restore ( flags ) ;
2009-05-14 02:56:35 +04:00
return temp ;
}
/**
* atomic_sub_return - subtract integer from atomic variable
* @ i : integer value to subtract
* @ v : pointer of type atomic_t
*
* Atomically subtracts @ i from @ v and returns the result
*/
static inline int atomic_sub_return ( int i , atomic_t * v )
{
unsigned long flags ;
int temp ;
2010-08-10 04:18:24 +04:00
raw_local_irq_save ( flags ) ; /* Don't trace it in a irqsoff handler */
2009-05-14 02:56:35 +04:00
temp = v - > counter ;
temp - = i ;
v - > counter = temp ;
2010-08-10 04:18:24 +04:00
raw_local_irq_restore ( flags ) ;
2009-05-14 02:56:35 +04:00
return temp ;
}
static inline int atomic_add_negative ( int i , atomic_t * v )
{
return atomic_add_return ( i , v ) < 0 ;
}
static inline void atomic_add ( int i , atomic_t * v )
{
atomic_add_return ( i , v ) ;
}
static inline void atomic_sub ( int i , atomic_t * v )
{
atomic_sub_return ( i , v ) ;
}
static inline void atomic_inc ( atomic_t * v )
{
atomic_add_return ( 1 , v ) ;
}
static inline void atomic_dec ( atomic_t * v )
{
atomic_sub_return ( 1 , v ) ;
}
# define atomic_dec_return(v) atomic_sub_return(1, (v))
# define atomic_inc_return(v) atomic_add_return(1, (v))
# define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0)
# define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
# define atomic_inc_and_test(v) (atomic_add_return(1, (v)) == 0)
# define atomic_add_unless(v, a, u) \
( { \
int c , old ; \
c = atomic_read ( v ) ; \
while ( c ! = ( u ) & & ( old = atomic_cmpxchg ( ( v ) , c , c + ( a ) ) ) ! = c ) \
c = old ; \
c ! = ( u ) ; \
} )
# define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
static inline void atomic_clear_mask ( unsigned long mask , unsigned long * addr )
{
unsigned long flags ;
mask = ~ mask ;
2010-08-10 04:18:24 +04:00
raw_local_irq_save ( flags ) ; /* Don't trace it in a irqsoff handler */
2009-05-14 02:56:35 +04:00
* addr & = mask ;
2010-08-10 04:18:24 +04:00
raw_local_irq_restore ( flags ) ;
2009-05-14 02:56:35 +04:00
}
# define atomic_xchg(ptr, v) (xchg(&(ptr)->counter, (v)))
# define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new)))
# define cmpxchg_local(ptr, o, n) \
( ( __typeof__ ( * ( ptr ) ) ) __cmpxchg_local_generic ( ( ptr ) , ( unsigned long ) ( o ) , \
( unsigned long ) ( n ) , sizeof ( * ( ptr ) ) ) )
# define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
/* Assume that atomic operations are already serializing */
# define smp_mb__before_atomic_dec() barrier()
# define smp_mb__after_atomic_dec() barrier()
# define smp_mb__before_atomic_inc() barrier()
# define smp_mb__after_atomic_inc() barrier()
# include <asm-generic/atomic-long.h>
# endif /* __KERNEL__ */
# endif /* __ASM_GENERIC_ATOMIC_H */