Home | History | Annotate | Download | only in asm-mips
      1 #ifndef _ARCH_MIPS_LOCAL_H
      2 #define _ARCH_MIPS_LOCAL_H
      3 
      4 #include <linux/percpu.h>
      5 #include <linux/bitops.h>
      6 #include <asm/atomic.h>
      7 #include <asm/cmpxchg.h>
      8 #include <asm/war.h>
      9 
     10 typedef struct
     11 {
     12 	atomic_long_t a;
     13 } local_t;
     14 
     15 #define LOCAL_INIT(i)	{ ATOMIC_LONG_INIT(i) }
     16 
     17 #define local_read(l)	atomic_long_read(&(l)->a)
     18 #define local_set(l, i)	atomic_long_set(&(l)->a, (i))
     19 
     20 #define local_add(i, l)	atomic_long_add((i), (&(l)->a))
     21 #define local_sub(i, l)	atomic_long_sub((i), (&(l)->a))
     22 #define local_inc(l)	atomic_long_inc(&(l)->a)
     23 #define local_dec(l)	atomic_long_dec(&(l)->a)
     24 
     25 /*
     26  * Same as above, but return the result value
     27  */
     28 static __inline__ long local_add_return(long i, local_t * l)
     29 {
     30 	unsigned long result;
     31 
     32 	if (cpu_has_llsc && R10000_LLSC_WAR) {
     33 		unsigned long temp;
     34 
     35 		__asm__ __volatile__(
     36 		"	.set	mips3					\n"
     37 		"1:"	__LL	"%1, %2		# local_add_return	\n"
     38 		"	addu	%0, %1, %3				\n"
     39 			__SC	"%0, %2					\n"
     40 		"	beqzl	%0, 1b					\n"
     41 		"	addu	%0, %1, %3				\n"
     42 		"	.set	mips0					\n"
     43 		: "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
     44 		: "Ir" (i), "m" (l->a.counter)
     45 		: "memory");
     46 	} else if (cpu_has_llsc) {
     47 		unsigned long temp;
     48 
     49 		__asm__ __volatile__(
     50 		"	.set	mips3					\n"
     51 		"1:"	__LL	"%1, %2		# local_add_return	\n"
     52 		"	addu	%0, %1, %3				\n"
     53 			__SC	"%0, %2					\n"
     54 		"	beqz	%0, 1b					\n"
     55 		"	addu	%0, %1, %3				\n"
     56 		"	.set	mips0					\n"
     57 		: "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
     58 		: "Ir" (i), "m" (l->a.counter)
     59 		: "memory");
     60 	} else {
     61 		unsigned long flags;
     62 
     63 		local_irq_save(flags);
     64 		result = l->a.counter;
     65 		result += i;
     66 		l->a.counter = result;
     67 		local_irq_restore(flags);
     68 	}
     69 
     70 	return result;
     71 }
     72 
     73 static __inline__ long local_sub_return(long i, local_t * l)
     74 {
     75 	unsigned long result;
     76 
     77 	if (cpu_has_llsc && R10000_LLSC_WAR) {
     78 		unsigned long temp;
     79 
     80 		__asm__ __volatile__(
     81 		"	.set	mips3					\n"
     82 		"1:"	__LL	"%1, %2		# local_sub_return	\n"
     83 		"	subu	%0, %1, %3				\n"
     84 			__SC	"%0, %2					\n"
     85 		"	beqzl	%0, 1b					\n"
     86 		"	subu	%0, %1, %3				\n"
     87 		"	.set	mips0					\n"
     88 		: "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
     89 		: "Ir" (i), "m" (l->a.counter)
     90 		: "memory");
     91 	} else if (cpu_has_llsc) {
     92 		unsigned long temp;
     93 
     94 		__asm__ __volatile__(
     95 		"	.set	mips3					\n"
     96 		"1:"	__LL	"%1, %2		# local_sub_return	\n"
     97 		"	subu	%0, %1, %3				\n"
     98 			__SC	"%0, %2					\n"
     99 		"	beqz	%0, 1b					\n"
    100 		"	subu	%0, %1, %3				\n"
    101 		"	.set	mips0					\n"
    102 		: "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
    103 		: "Ir" (i), "m" (l->a.counter)
    104 		: "memory");
    105 	} else {
    106 		unsigned long flags;
    107 
    108 		local_irq_save(flags);
    109 		result = l->a.counter;
    110 		result -= i;
    111 		l->a.counter = result;
    112 		local_irq_restore(flags);
    113 	}
    114 
    115 	return result;
    116 }
    117 
    118 #define local_cmpxchg(l, o, n) \
    119 	((long)cmpxchg_local(&((l)->a.counter), (o), (n)))
    120 #define local_xchg(l, n) (xchg_local(&((l)->a.counter), (n)))
    121 
    122 /**
    123  * local_add_unless - add unless the number is a given value
    124  * @l: pointer of type local_t
    125  * @a: the amount to add to l...
    126  * @u: ...unless l is equal to u.
    127  *
    128  * Atomically adds @a to @l, so long as it was not @u.
    129  * Returns non-zero if @l was not @u, and zero otherwise.
    130  */
    131 #define local_add_unless(l, a, u)				\
    132 ({								\
    133 	long c, old;						\
    134 	c = local_read(l);					\
    135 	while (c != (u) && (old = local_cmpxchg((l), c, c + (a))) != c) \
    136 		c = old;					\
    137 	c != (u);						\
    138 })
    139 #define local_inc_not_zero(l) local_add_unless((l), 1, 0)
    140 
    141 #define local_dec_return(l) local_sub_return(1, (l))
    142 #define local_inc_return(l) local_add_return(1, (l))
    143 
    144 /*
    145  * local_sub_and_test - subtract value from variable and test result
    146  * @i: integer value to subtract
    147  * @l: pointer of type local_t
    148  *
    149  * Atomically subtracts @i from @l and returns
    150  * true if the result is zero, or false for all
    151  * other cases.
    152  */
    153 #define local_sub_and_test(i, l) (local_sub_return((i), (l)) == 0)
    154 
    155 /*
    156  * local_inc_and_test - increment and test
    157  * @l: pointer of type local_t
    158  *
    159  * Atomically increments @l by 1
    160  * and returns true if the result is zero, or false for all
    161  * other cases.
    162  */
    163 #define local_inc_and_test(l) (local_inc_return(l) == 0)
    164 
    165 /*
    166  * local_dec_and_test - decrement by 1 and test
    167  * @l: pointer of type local_t
    168  *
    169  * Atomically decrements @l by 1 and
    170  * returns true if the result is 0, or false for all other
    171  * cases.
    172  */
    173 #define local_dec_and_test(l) (local_sub_return(1, (l)) == 0)
    174 
    175 /*
    176  * local_add_negative - add and test if negative
    177  * @l: pointer of type local_t
    178  * @i: integer value to add
    179  *
    180  * Atomically adds @i to @l and returns true
    181  * if the result is negative, or false when
    182  * result is greater than or equal to zero.
    183  */
    184 #define local_add_negative(i, l) (local_add_return(i, (l)) < 0)
    185 
    186 /* Use these for per-cpu local_t variables: on some archs they are
    187  * much more efficient than these naive implementations.  Note they take
    188  * a variable, not an address.
    189  */
    190 
    191 #define __local_inc(l)		((l)->a.counter++)
    192 #define __local_dec(l)		((l)->a.counter++)
    193 #define __local_add(i, l)	((l)->a.counter+=(i))
    194 #define __local_sub(i, l)	((l)->a.counter-=(i))
    195 
    196 /* Need to disable preemption for the cpu local counters otherwise we could
    197    still access a variable of a previous CPU in a non atomic way. */
    198 #define cpu_local_wrap_v(l)	 	\
    199 	({ local_t res__;		\
    200 	   preempt_disable(); 		\
    201 	   res__ = (l);			\
    202 	   preempt_enable();		\
    203 	   res__; })
    204 #define cpu_local_wrap(l)		\
    205 	({ preempt_disable();		\
    206 	   l;				\
    207 	   preempt_enable(); })		\
    208 
    209 #define cpu_local_read(l)    cpu_local_wrap_v(local_read(&__get_cpu_var(l)))
    210 #define cpu_local_set(l, i)  cpu_local_wrap(local_set(&__get_cpu_var(l), (i)))
    211 #define cpu_local_inc(l)     cpu_local_wrap(local_inc(&__get_cpu_var(l)))
    212 #define cpu_local_dec(l)     cpu_local_wrap(local_dec(&__get_cpu_var(l)))
    213 #define cpu_local_add(i, l)  cpu_local_wrap(local_add((i), &__get_cpu_var(l)))
    214 #define cpu_local_sub(i, l)  cpu_local_wrap(local_sub((i), &__get_cpu_var(l)))
    215 
    216 #define __cpu_local_inc(l)	cpu_local_inc(l)
    217 #define __cpu_local_dec(l)	cpu_local_dec(l)
    218 #define __cpu_local_add(i, l)	cpu_local_add((i), (l))
    219 #define __cpu_local_sub(i, l)	cpu_local_sub((i), (l))
    220 
    221 #endif /* _ARCH_MIPS_LOCAL_H */
    222