2010-01-07 11:53:33 -05:00
# ifndef _ASM_X86_ATOMIC64_32_H
# define _ASM_X86_ATOMIC64_32_H
# include <linux/compiler.h>
# include <linux/types.h>
# include <asm/processor.h>
//#include <asm/cmpxchg.h>
/* An 64bit atomic type */
typedef struct {
u64 __aligned ( 8 ) counter ;
} atomic64_t ;
# define ATOMIC64_INIT(val) { (val) }
2012-01-20 16:21:41 +00:00
# define __ATOMIC64_DECL(sym) void atomic64_##sym(atomic64_t *, ...)
# ifndef ATOMIC64_EXPORT
# define ATOMIC64_DECL_ONE __ATOMIC64_DECL
# else
# define ATOMIC64_DECL_ONE(sym) __ATOMIC64_DECL(sym); \
ATOMIC64_EXPORT ( atomic64_ # # sym )
# endif
2010-02-24 10:54:25 +01:00
# ifdef CONFIG_X86_CMPXCHG64
2012-01-20 16:21:41 +00:00
# define __alternative_atomic64(f, g, out, in...) \
asm volatile ( " call %P[func] " \
: out : [ func ] " i " ( atomic64_ # # g # # _cx8 ) , # # in )
# define ATOMIC64_DECL(sym) ATOMIC64_DECL_ONE(sym##_cx8)
2010-02-24 10:54:25 +01:00
# else
2012-01-20 16:21:41 +00:00
# define __alternative_atomic64(f, g, out, in...) \
alternative_call ( atomic64_ # # f # # _386 , atomic64_ # # g # # _cx8 , \
X86_FEATURE_CX8 , ASM_OUTPUT2 ( out ) , # # in )
# define ATOMIC64_DECL(sym) ATOMIC64_DECL_ONE(sym##_cx8); \
ATOMIC64_DECL_ONE ( sym # # _386 )
ATOMIC64_DECL_ONE ( add_386 ) ;
ATOMIC64_DECL_ONE ( sub_386 ) ;
ATOMIC64_DECL_ONE ( inc_386 ) ;
ATOMIC64_DECL_ONE ( dec_386 ) ;
2010-02-24 10:54:25 +01:00
# endif
2012-01-20 16:21:41 +00:00
# define alternative_atomic64(f, out, in...) \
__alternative_atomic64 ( f , f , ASM_OUTPUT2 ( out ) , # # in )
ATOMIC64_DECL ( read ) ;
ATOMIC64_DECL ( set ) ;
ATOMIC64_DECL ( xchg ) ;
ATOMIC64_DECL ( add_return ) ;
ATOMIC64_DECL ( sub_return ) ;
ATOMIC64_DECL ( inc_return ) ;
ATOMIC64_DECL ( dec_return ) ;
ATOMIC64_DECL ( dec_if_positive ) ;
ATOMIC64_DECL ( inc_not_zero ) ;
ATOMIC64_DECL ( add_unless ) ;
# undef ATOMIC64_DECL
# undef ATOMIC64_DECL_ONE
# undef __ATOMIC64_DECL
# undef ATOMIC64_EXPORT
2010-02-24 10:54:25 +01:00
/**
* atomic64_cmpxchg - cmpxchg atomic64 variable
2012-05-02 18:09:35 +02:00
* @ v : pointer to type atomic64_t
2010-02-24 10:54:25 +01:00
* @ o : expected value
* @ n : new value
*
* Atomically sets @ v to @ n if it was equal to @ o and returns
* the old value .
*/
static inline long long atomic64_cmpxchg ( atomic64_t * v , long long o , long long n )
{
return cmpxchg64 ( & v - > counter , o , n ) ;
}
2010-01-07 11:53:33 -05:00
/**
* atomic64_xchg - xchg atomic64 variable
2010-02-24 10:54:25 +01:00
* @ v : pointer to type atomic64_t
* @ n : value to assign
2010-01-07 11:53:33 -05:00
*
2010-02-24 10:54:25 +01:00
* Atomically xchgs the value of @ v to @ n and returns
2010-01-07 11:53:33 -05:00
* the old value .
*/
2010-02-24 10:54:25 +01:00
static inline long long atomic64_xchg ( atomic64_t * v , long long n )
{
long long o ;
unsigned high = ( unsigned ) ( n > > 32 ) ;
unsigned low = ( unsigned ) n ;
2012-01-20 16:21:41 +00:00
alternative_atomic64 ( xchg , " =&A " ( o ) ,
" S " ( v ) , " b " ( low ) , " c " ( high )
: " memory " ) ;
2010-02-24 10:54:25 +01:00
return o ;
}
2010-01-07 11:53:33 -05:00
/**
* atomic64_set - set atomic64 variable
2010-02-24 10:54:25 +01:00
* @ v : pointer to type atomic64_t
2012-05-02 18:09:35 +02:00
* @ i : value to assign
2010-01-07 11:53:33 -05:00
*
2010-02-24 10:54:25 +01:00
* Atomically sets the value of @ v to @ n .
2010-01-07 11:53:33 -05:00
*/
2010-02-24 10:54:25 +01:00
static inline void atomic64_set ( atomic64_t * v , long long i )
{
unsigned high = ( unsigned ) ( i > > 32 ) ;
unsigned low = ( unsigned ) i ;
2012-01-20 16:21:41 +00:00
alternative_atomic64 ( set , /* no output */ ,
" S " ( v ) , " b " ( low ) , " c " ( high )
: " eax " , " edx " , " memory " ) ;
2010-02-24 10:54:25 +01:00
}
2010-01-07 11:53:33 -05:00
/**
* atomic64_read - read atomic64 variable
2010-02-24 10:54:25 +01:00
* @ v : pointer to type atomic64_t
2010-01-07 11:53:33 -05:00
*
2010-02-24 10:54:25 +01:00
* Atomically reads the value of @ v and returns it .
2010-01-07 11:53:33 -05:00
*/
2012-01-09 19:33:24 -08:00
static inline long long atomic64_read ( const atomic64_t * v )
2010-01-07 11:53:33 -05:00
{
2010-02-24 10:54:25 +01:00
long long r ;
2012-01-20 16:21:41 +00:00
alternative_atomic64 ( read , " =&A " ( r ) , " c " ( v ) : " memory " ) ;
2010-02-24 10:54:25 +01:00
return r ;
}
2010-01-07 11:53:33 -05:00
/**
* atomic64_add_return - add and return
2010-02-24 10:54:25 +01:00
* @ i : integer value to add
* @ v : pointer to type atomic64_t
2010-01-07 11:53:33 -05:00
*
2010-02-24 10:54:25 +01:00
* Atomically adds @ i to @ v and returns @ i + * @ v
2010-01-07 11:53:33 -05:00
*/
2010-02-24 10:54:25 +01:00
static inline long long atomic64_add_return ( long long i , atomic64_t * v )
{
2012-01-20 16:21:41 +00:00
alternative_atomic64 ( add_return ,
ASM_OUTPUT2 ( " +A " ( i ) , " +c " ( v ) ) ,
ASM_NO_INPUT_CLOBBER ( " memory " ) ) ;
2010-02-24 10:54:25 +01:00
return i ;
}
2010-01-07 11:53:33 -05:00
/*
* Other variants with different arithmetic operators :
*/
2010-02-24 10:54:25 +01:00
static inline long long atomic64_sub_return ( long long i , atomic64_t * v )
{
2012-01-20 16:21:41 +00:00
alternative_atomic64 ( sub_return ,
ASM_OUTPUT2 ( " +A " ( i ) , " +c " ( v ) ) ,
ASM_NO_INPUT_CLOBBER ( " memory " ) ) ;
2010-02-24 10:54:25 +01:00
return i ;
}
static inline long long atomic64_inc_return ( atomic64_t * v )
{
long long a ;
2012-01-20 16:21:41 +00:00
alternative_atomic64 ( inc_return , " =&A " ( a ) ,
" S " ( v ) : " memory " , " ecx " ) ;
2010-02-24 10:54:25 +01:00
return a ;
}
static inline long long atomic64_dec_return ( atomic64_t * v )
{
long long a ;
2012-01-20 16:21:41 +00:00
alternative_atomic64 ( dec_return , " =&A " ( a ) ,
" S " ( v ) : " memory " , " ecx " ) ;
2010-02-24 10:54:25 +01:00
return a ;
}
2010-01-07 11:53:33 -05:00
/**
* atomic64_add - add integer to atomic64 variable
2010-02-24 10:54:25 +01:00
* @ i : integer value to add
* @ v : pointer to type atomic64_t
2010-01-07 11:53:33 -05:00
*
2010-02-24 10:54:25 +01:00
* Atomically adds @ i to @ v .
2010-01-07 11:53:33 -05:00
*/
2010-02-24 10:54:25 +01:00
static inline long long atomic64_add ( long long i , atomic64_t * v )
{
2012-01-20 16:21:41 +00:00
__alternative_atomic64 ( add , add_return ,
ASM_OUTPUT2 ( " +A " ( i ) , " +c " ( v ) ) ,
ASM_NO_INPUT_CLOBBER ( " memory " ) ) ;
2010-02-24 10:54:25 +01:00
return i ;
}
2010-01-07 11:53:33 -05:00
/**
* atomic64_sub - subtract the atomic64 variable
2010-02-24 10:54:25 +01:00
* @ i : integer value to subtract
* @ v : pointer to type atomic64_t
2010-01-07 11:53:33 -05:00
*
2010-02-24 10:54:25 +01:00
* Atomically subtracts @ i from @ v .
2010-01-07 11:53:33 -05:00
*/
2010-02-24 10:54:25 +01:00
static inline long long atomic64_sub ( long long i , atomic64_t * v )
{
2012-01-20 16:21:41 +00:00
__alternative_atomic64 ( sub , sub_return ,
ASM_OUTPUT2 ( " +A " ( i ) , " +c " ( v ) ) ,
ASM_NO_INPUT_CLOBBER ( " memory " ) ) ;
2010-02-24 10:54:25 +01:00
return i ;
}
2010-01-07 11:53:33 -05:00
/**
* atomic64_sub_and_test - subtract value from variable and test result
2010-02-24 10:54:25 +01:00
* @ i : integer value to subtract
* @ v : pointer to type atomic64_t
2012-05-02 18:09:35 +02:00
*
2010-02-24 10:54:25 +01:00
* Atomically subtracts @ i from @ v and returns
2010-01-07 11:53:33 -05:00
* true if the result is zero , or false for all
* other cases .
*/
2010-02-24 10:54:25 +01:00
static inline int atomic64_sub_and_test ( long long i , atomic64_t * v )
{
return atomic64_sub_return ( i , v ) = = 0 ;
}
2010-01-07 11:53:33 -05:00
/**
* atomic64_inc - increment atomic64 variable
2010-02-24 10:54:25 +01:00
* @ v : pointer to type atomic64_t
2010-01-07 11:53:33 -05:00
*
2010-02-24 10:54:25 +01:00
* Atomically increments @ v by 1.
2010-01-07 11:53:33 -05:00
*/
2010-02-24 10:54:25 +01:00
static inline void atomic64_inc ( atomic64_t * v )
{
2012-01-20 16:21:41 +00:00
__alternative_atomic64 ( inc , inc_return , /* no output */ ,
" S " ( v ) : " memory " , " eax " , " ecx " , " edx " ) ;
2010-02-24 10:54:25 +01:00
}
2010-01-07 11:53:33 -05:00
/**
* atomic64_dec - decrement atomic64 variable
2012-05-02 18:09:35 +02:00
* @ v : pointer to type atomic64_t
2010-01-07 11:53:33 -05:00
*
2012-05-02 18:09:35 +02:00
* Atomically decrements @ v by 1.
2010-01-07 11:53:33 -05:00
*/
2010-02-24 10:54:25 +01:00
static inline void atomic64_dec ( atomic64_t * v )
{
2012-01-20 16:21:41 +00:00
__alternative_atomic64 ( dec , dec_return , /* no output */ ,
" S " ( v ) : " memory " , " eax " , " ecx " , " edx " ) ;
2010-02-24 10:54:25 +01:00
}
2010-01-07 11:53:33 -05:00
/**
* atomic64_dec_and_test - decrement and test
2010-02-24 10:54:25 +01:00
* @ v : pointer to type atomic64_t
2010-01-07 11:53:33 -05:00
*
2010-02-24 10:54:25 +01:00
* Atomically decrements @ v by 1 and
2010-01-07 11:53:33 -05:00
* returns true if the result is 0 , or false for all other
* cases .
*/
2010-02-24 10:54:25 +01:00
static inline int atomic64_dec_and_test ( atomic64_t * v )
{
return atomic64_dec_return ( v ) = = 0 ;
}
2010-01-07 11:53:33 -05:00
/**
* atomic64_inc_and_test - increment and test
2010-02-24 10:54:25 +01:00
* @ v : pointer to type atomic64_t
2010-01-07 11:53:33 -05:00
*
2010-02-24 10:54:25 +01:00
* Atomically increments @ v by 1
2010-01-07 11:53:33 -05:00
* and returns true if the result is zero , or false for all
* other cases .
*/
2010-02-24 10:54:25 +01:00
static inline int atomic64_inc_and_test ( atomic64_t * v )
{
return atomic64_inc_return ( v ) = = 0 ;
}
2010-01-07 11:53:33 -05:00
/**
* atomic64_add_negative - add and test if negative
2010-02-24 10:54:25 +01:00
* @ i : integer value to add
* @ v : pointer to type atomic64_t
2010-01-07 11:53:33 -05:00
*
2010-02-24 10:54:25 +01:00
* Atomically adds @ i to @ v and returns true
2010-01-07 11:53:33 -05:00
* if the result is negative , or false when
* result is greater than or equal to zero .
*/
2010-02-24 10:54:25 +01:00
static inline int atomic64_add_negative ( long long i , atomic64_t * v )
{
return atomic64_add_return ( i , v ) < 0 ;
}
/**
* atomic64_add_unless - add unless the number is a given value
* @ v : pointer of type atomic64_t
* @ a : the amount to add to v . . .
* @ u : . . . unless v is equal to u .
*
* Atomically adds @ a to @ v , so long as it was not @ u .
2012-01-20 16:21:41 +00:00
* Returns non - zero if the add was done , zero otherwise .
2010-02-24 10:54:25 +01:00
*/
static inline int atomic64_add_unless ( atomic64_t * v , long long a , long long u )
{
unsigned low = ( unsigned ) u ;
unsigned high = ( unsigned ) ( u > > 32 ) ;
2012-01-20 16:21:41 +00:00
alternative_atomic64 ( add_unless ,
2012-01-20 16:22:04 +00:00
ASM_OUTPUT2 ( " +A " ( a ) , " +c " ( low ) , " +D " ( high ) ) ,
" S " ( v ) : " memory " ) ;
2010-02-24 10:54:25 +01:00
return ( int ) a ;
}
static inline int atomic64_inc_not_zero ( atomic64_t * v )
{
int r ;
2012-01-20 16:21:41 +00:00
alternative_atomic64 ( inc_not_zero , " =&a " ( r ) ,
" S " ( v ) : " ecx " , " edx " , " memory " ) ;
2010-02-24 10:54:25 +01:00
return r ;
}
static inline long long atomic64_dec_if_positive ( atomic64_t * v )
{
long long r ;
2012-01-20 16:21:41 +00:00
alternative_atomic64 ( dec_if_positive , " =&A " ( r ) ,
" S " ( v ) : " ecx " , " memory " ) ;
2010-02-24 10:54:25 +01:00
return r ;
}
2012-01-20 16:21:41 +00:00
# undef alternative_atomic64
# undef __alternative_atomic64
2010-01-07 11:53:33 -05:00
2014-04-23 20:28:37 +02:00
# define ATOMIC64_OP(op, c_op) \
static inline void atomic64_ # # op ( long long i , atomic64_t * v ) \
{ \
long long old , c = 0 ; \
while ( ( old = atomic64_cmpxchg ( v , c , c c_op i ) ) ! = c ) \
c = old ; \
}
ATOMIC64_OP ( and , & )
ATOMIC64_OP ( or , | )
ATOMIC64_OP ( xor , ^ )
# undef ATOMIC64_OP
2010-01-07 11:53:33 -05:00
# endif /* _ASM_X86_ATOMIC64_32_H */