diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-13 09:48:00 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-13 09:48:00 -0400 |
commit | dbb885fecc1b1b35e93416bedd24d21bd20f60ed (patch) | |
tree | 9aa92bcc4e3d3594eba0ba85d72b878d85f35a59 | |
parent | d6dd50e07c5bec00db2005969b1a01f8ca3d25ef (diff) | |
parent | 2291059c852706c6f5ffb400366042b7625066cd (diff) |
Merge branch 'locking-arch-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull arch atomic cleanups from Ingo Molnar:
"This is a series kept separate from the main locking tree, which
cleans up and improves various details in the atomics type handling:
- Remove the unused atomic_or_long() method
- Consolidate and compress atomic ops implementations between
architectures, to reduce linecount and to make it easier to add new
ops.
- Rewrite generic atomic support to only require cmpxchg() from an
architecture - generate all other methods from that"
* 'locking-arch-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (23 commits)
locking,arch: Use ACCESS_ONCE() instead of cast to volatile in atomic_read()
locking, mips: Fix atomics
locking, sparc64: Fix atomics
locking,arch: Rewrite generic atomic support
locking,arch,xtensa: Fold atomic_ops
locking,arch,sparc: Fold atomic_ops
locking,arch,sh: Fold atomic_ops
locking,arch,powerpc: Fold atomic_ops
locking,arch,parisc: Fold atomic_ops
locking,arch,mn10300: Fold atomic_ops
locking,arch,mips: Fold atomic_ops
locking,arch,metag: Fold atomic_ops
locking,arch,m68k: Fold atomic_ops
locking,arch,m32r: Fold atomic_ops
locking,arch,ia64: Fold atomic_ops
locking,arch,hexagon: Fold atomic_ops
locking,arch,cris: Fold atomic_ops
locking,arch,avr32: Fold atomic_ops
locking,arch,arm64: Fold atomic_ops
locking,arch,arm: Fold atomic_ops
...
33 files changed, 1611 insertions, 2320 deletions
diff --git a/arch/alpha/include/asm/atomic.h b/arch/alpha/include/asm/atomic.h index ed60a1ee1ed3..8f8eafbedd7c 100644 --- a/arch/alpha/include/asm/atomic.h +++ b/arch/alpha/include/asm/atomic.h | |||
@@ -17,8 +17,8 @@ | |||
17 | #define ATOMIC_INIT(i) { (i) } | 17 | #define ATOMIC_INIT(i) { (i) } |
18 | #define ATOMIC64_INIT(i) { (i) } | 18 | #define ATOMIC64_INIT(i) { (i) } |
19 | 19 | ||
20 | #define atomic_read(v) (*(volatile int *)&(v)->counter) | 20 | #define atomic_read(v) ACCESS_ONCE((v)->counter) |
21 | #define atomic64_read(v) (*(volatile long *)&(v)->counter) | 21 | #define atomic64_read(v) ACCESS_ONCE((v)->counter) |
22 | 22 | ||
23 | #define atomic_set(v,i) ((v)->counter = (i)) | 23 | #define atomic_set(v,i) ((v)->counter = (i)) |
24 | #define atomic64_set(v,i) ((v)->counter = (i)) | 24 | #define atomic64_set(v,i) ((v)->counter = (i)) |
@@ -29,145 +29,92 @@ | |||
29 | * branch back to restart the operation. | 29 | * branch back to restart the operation. |
30 | */ | 30 | */ |
31 | 31 | ||
32 | static __inline__ void atomic_add(int i, atomic_t * v) | 32 | #define ATOMIC_OP(op) \ |
33 | { | 33 | static __inline__ void atomic_##op(int i, atomic_t * v) \ |
34 | unsigned long temp; | 34 | { \ |
35 | __asm__ __volatile__( | 35 | unsigned long temp; \ |
36 | "1: ldl_l %0,%1\n" | 36 | __asm__ __volatile__( \ |
37 | " addl %0,%2,%0\n" | 37 | "1: ldl_l %0,%1\n" \ |
38 | " stl_c %0,%1\n" | 38 | " " #op "l %0,%2,%0\n" \ |
39 | " beq %0,2f\n" | 39 | " stl_c %0,%1\n" \ |
40 | ".subsection 2\n" | 40 | " beq %0,2f\n" \ |
41 | "2: br 1b\n" | 41 | ".subsection 2\n" \ |
42 | ".previous" | 42 | "2: br 1b\n" \ |
43 | :"=&r" (temp), "=m" (v->counter) | 43 | ".previous" \ |
44 | :"Ir" (i), "m" (v->counter)); | 44 | :"=&r" (temp), "=m" (v->counter) \ |
45 | } | 45 | :"Ir" (i), "m" (v->counter)); \ |
46 | 46 | } \ | |
47 | static __inline__ void atomic64_add(long i, atomic64_t * v) | 47 | |
48 | { | 48 | #define ATOMIC_OP_RETURN(op) \ |
49 | unsigned long temp; | 49 | static inline int atomic_##op##_return(int i, atomic_t *v) \ |
50 | __asm__ __volatile__( | 50 | { \ |
51 | "1: ldq_l %0,%1\n" | 51 | long temp, result; \ |
52 | " addq %0,%2,%0\n" | 52 | smp_mb(); \ |
53 | " stq_c %0,%1\n" | 53 | __asm__ __volatile__( \ |
54 | " beq %0,2f\n" | 54 | "1: ldl_l %0,%1\n" \ |
55 | ".subsection 2\n" | 55 | " " #op "l %0,%3,%2\n" \ |
56 | "2: br 1b\n" | 56 | " " #op "l %0,%3,%0\n" \ |
57 | ".previous" | 57 | " stl_c %0,%1\n" \ |
58 | :"=&r" (temp), "=m" (v->counter) | 58 | " beq %0,2f\n" \ |
59 | :"Ir" (i), "m" (v->counter)); | 59 | ".subsection 2\n" \ |
60 | } | 60 | "2: br 1b\n" \ |
61 | 61 | ".previous" \ | |
62 | static __inline__ void atomic_sub(int i, atomic_t * v) | 62 | :"=&r" (temp), "=m" (v->counter), "=&r" (result) \ |
63 | { | 63 | :"Ir" (i), "m" (v->counter) : "memory"); \ |
64 | unsigned long temp; | 64 | smp_mb(); \ |
65 | __asm__ __volatile__( | 65 | return result; \ |
66 | "1: ldl_l %0,%1\n" | ||
67 | " subl %0,%2,%0\n" | ||
68 | " stl_c %0,%1\n" | ||
69 | " beq %0,2f\n" | ||
70 | ".subsection 2\n" | ||
71 | "2: br 1b\n" | ||
72 | ".previous" | ||
73 | :"=&r" (temp), "=m" (v->counter) | ||
74 | :"Ir" (i), "m" (v->counter)); | ||
75 | } | 66 | } |
76 | 67 | ||
77 | static __inline__ void atomic64_sub(long i, atomic64_t * v) | 68 | #define ATOMIC64_OP(op) \ |
78 | { | 69 | static __inline__ void atomic64_##op(long i, atomic64_t * v) \ |
79 | unsigned long temp; | 70 | { \ |
80 | __asm__ __volatile__( | 71 | unsigned long temp; \ |
81 | "1: ldq_l %0,%1\n" | 72 | __asm__ __volatile__( \ |
82 | " subq %0,%2,%0\n" | 73 | "1: ldq_l %0,%1\n" \ |
83 | " stq_c %0,%1\n" | 74 | " " #op "q %0,%2,%0\n" \ |
84 | " beq %0,2f\n" | 75 | " stq_c %0,%1\n" \ |
85 | ".subsection 2\n" | 76 | " beq %0,2f\n" \ |
86 | "2: br 1b\n" | 77 | ".subsection 2\n" \ |
87 | ".previous" | 78 | "2: br 1b\n" \ |
88 | :"=&r" (temp), "=m" (v->counter) | 79 | ".previous" \ |
89 | :"Ir" (i), "m" (v->counter)); | 80 | :"=&r" (temp), "=m" (v->counter) \ |
90 | } | 81 | :"Ir" (i), "m" (v->counter)); \ |
91 | 82 | } \ | |
92 | 83 | ||
93 | /* | 84 | #define ATOMIC64_OP_RETURN(op) \ |
94 | * Same as above, but return the result value | 85 | static __inline__ long atomic64_##op##_return(long i, atomic64_t * v) \ |
95 | */ | 86 | { \ |
96 | static inline int atomic_add_return(int i, atomic_t *v) | 87 | long temp, result; \ |
97 | { | 88 | smp_mb(); \ |
98 | long temp, result; | 89 | __asm__ __volatile__( \ |
99 | smp_mb(); | 90 | "1: ldq_l %0,%1\n" \ |
100 | __asm__ __volatile__( | 91 | " " #op "q %0,%3,%2\n" \ |
101 | "1: ldl_l %0,%1\n" | 92 | " " #op "q %0,%3,%0\n" \ |
102 | " addl %0,%3,%2\n" | 93 | " stq_c %0,%1\n" \ |
103 | " addl %0,%3,%0\n" | 94 | " beq %0,2f\n" \ |
104 | " stl_c %0,%1\n" | 95 | ".subsection 2\n" \ |
105 | " beq %0,2f\n" | 96 | "2: br 1b\n" \ |
106 | ".subsection 2\n" | 97 | ".previous" \ |
107 | "2: br 1b\n" | 98 | :"=&r" (temp), "=m" (v->counter), "=&r" (result) \ |
108 | ".previous" | 99 | :"Ir" (i), "m" (v->counter) : "memory"); \ |
109 | :"=&r" (temp), "=m" (v->counter), "=&r" (result) | 100 | smp_mb(); \ |
110 | :"Ir" (i), "m" (v->counter) : "memory"); | 101 | return result; \ |
111 | smp_mb(); | ||
112 | return result; | ||
113 | } | 102 | } |
114 | 103 | ||
115 | static __inline__ long atomic64_add_return(long i, atomic64_t * v) | 104 | #define ATOMIC_OPS(opg) \ |
116 | { | 105 | ATOMIC_OP(opg) \ |
117 | long temp, result; | 106 | ATOMIC_OP_RETURN(opg) \ |
118 | smp_mb(); | 107 | ATOMIC64_OP(opg) \ |
119 | __asm__ __volatile__( | 108 | ATOMIC64_OP_RETURN(opg) |
120 | "1: ldq_l %0,%1\n" | ||
121 | " addq %0,%3,%2\n" | ||
122 | " addq %0,%3,%0\n" | ||
123 | " stq_c %0,%1\n" | ||
124 | " beq %0,2f\n" | ||
125 | ".subsection 2\n" | ||
126 | "2: br 1b\n" | ||
127 | ".previous" | ||
128 | :"=&r" (temp), "=m" (v->counter), "=&r" (result) | ||
129 | :"Ir" (i), "m" (v->counter) : "memory"); | ||
130 | smp_mb(); | ||
131 | return result; | ||
132 | } | ||
133 | 109 | ||
134 | static __inline__ long atomic_sub_return(int i, atomic_t * v) | 110 | ATOMIC_OPS(add) |
135 | { | 111 | ATOMIC_OPS(sub) |
136 | long temp, result; | ||
137 | smp_mb(); | ||
138 | __asm__ __volatile__( | ||
139 | "1: ldl_l %0,%1\n" | ||
140 | " subl %0,%3,%2\n" | ||
141 | " subl %0,%3,%0\n" | ||
142 | " stl_c %0,%1\n" | ||
143 | " beq %0,2f\n" | ||
144 | ".subsection 2\n" | ||
145 | "2: br 1b\n" | ||
146 | ".previous" | ||
147 | :"=&r" (temp), "=m" (v->counter), "=&r" (result) | ||
148 | :"Ir" (i), "m" (v->counter) : "memory"); | ||
149 | smp_mb(); | ||
150 | return result; | ||
151 | } | ||
152 | 112 | ||
153 | static __inline__ long atomic64_sub_return(long i, atomic64_t * v) | 113 | #undef ATOMIC_OPS |
154 | { | 114 | #undef ATOMIC64_OP_RETURN |
155 | long temp, result; | 115 | #undef ATOMIC64_OP |
156 | smp_mb(); | 116 | #undef ATOMIC_OP_RETURN |
157 | __asm__ __volatile__( | 117 | #undef ATOMIC_OP |
158 | "1: ldq_l %0,%1\n" | ||
159 | " subq %0,%3,%2\n" | ||
160 | " subq %0,%3,%0\n" | ||
161 | " stq_c %0,%1\n" | ||
162 | " beq %0,2f\n" | ||
163 | ".subsection 2\n" | ||
164 | "2: br 1b\n" | ||
165 | ".previous" | ||
166 | :"=&r" (temp), "=m" (v->counter), "=&r" (result) | ||
167 | :"Ir" (i), "m" (v->counter) : "memory"); | ||
168 | smp_mb(); | ||
169 | return result; | ||
170 | } | ||
171 | 118 | ||
172 | #define atomic64_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new)) | 119 | #define atomic64_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new)) |
173 | #define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) | 120 | #define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) |
diff --git a/arch/arc/include/asm/atomic.h b/arch/arc/include/asm/atomic.h index 83f03ca6caf6..173f303a868f 100644 --- a/arch/arc/include/asm/atomic.h +++ b/arch/arc/include/asm/atomic.h | |||
@@ -25,79 +25,36 @@ | |||
25 | 25 | ||
26 | #define atomic_set(v, i) (((v)->counter) = (i)) | 26 | #define atomic_set(v, i) (((v)->counter) = (i)) |
27 | 27 | ||
28 | static inline void atomic_add(int i, atomic_t *v) | 28 | #define ATOMIC_OP(op, c_op, asm_op) \ |
29 | { | 29 | static inline void atomic_##op(int i, atomic_t *v) \ |
30 | unsigned int temp; | 30 | { \ |
31 | 31 | unsigned int temp; \ | |
32 | __asm__ __volatile__( | 32 | \ |
33 | "1: llock %0, [%1] \n" | 33 | __asm__ __volatile__( \ |
34 | " add %0, %0, %2 \n" | 34 | "1: llock %0, [%1] \n" \ |
35 | " scond %0, [%1] \n" | 35 | " " #asm_op " %0, %0, %2 \n" \ |
36 | " bnz 1b \n" | 36 | " scond %0, [%1] \n" \ |
37 | : "=&r"(temp) /* Early clobber, to prevent reg reuse */ | 37 | " bnz 1b \n" \ |
38 | : "r"(&v->counter), "ir"(i) | 38 | : "=&r"(temp) /* Early clobber, to prevent reg reuse */ \ |
39 | : "cc"); | 39 | : "r"(&v->counter), "ir"(i) \ |
40 | } | 40 | : "cc"); \ |
41 | 41 | } \ | |
42 | static inline void atomic_sub(int i, atomic_t *v) | 42 | |
43 | { | 43 | #define ATOMIC_OP_RETURN(op, c_op, asm_op) \ |
44 | unsigned int temp; | 44 | static inline int atomic_##op##_return(int i, atomic_t *v) \ |
45 | 45 | { \ | |
46 | __asm__ __volatile__( | 46 | unsigned int temp; \ |
47 | "1: llock %0, [%1] \n" | 47 | \ |
48 | " sub %0, %0, %2 \n" | 48 | __asm__ __volatile__( \ |
49 | " scond %0, [%1] \n" | 49 | "1: llock %0, [%1] \n" \ |
50 | " bnz 1b \n" | 50 | " " #asm_op " %0, %0, %2 \n" \ |
51 | : "=&r"(temp) | 51 | " scond %0, [%1] \n" \ |
52 | : "r"(&v->counter), "ir"(i) | 52 | " bnz 1b \n" \ |
53 | : "cc"); | 53 | : "=&r"(temp) \ |
54 | } | 54 | : "r"(&v->counter), "ir"(i) \ |
55 | 55 | : "cc"); \ | |
56 | /* add and also return the new value */ | 56 | \ |
57 | static inline int atomic_add_return(int i, atomic_t *v) | 57 | return temp; \ |
58 | { | ||
59 | unsigned int temp; | ||
60 | |||
61 | __asm__ __volatile__( | ||
62 | "1: llock %0, [%1] \n" | ||
63 | " add %0, %0, %2 \n" | ||
64 | " scond %0, [%1] \n" | ||
65 | " bnz 1b \n" | ||
66 | : "=&r"(temp) | ||
67 | : "r"(&v->counter), "ir"(i) | ||
68 | : "cc"); | ||
69 | |||
70 | return temp; | ||
71 | } | ||
72 | |||
73 | static inline int atomic_sub_return(int i, atomic_t *v) | ||
74 | { | ||
75 | unsigned int temp; | ||
76 | |||
77 | __asm__ __volatile__( | ||
78 | "1: llock %0, [%1] \n" | ||
79 | " sub %0, %0, %2 \n" | ||
80 | " scond %0, [%1] \n" | ||
81 | " bnz 1b \n" | ||
82 | : "=&r"(temp) | ||
83 | : "r"(&v->counter), "ir"(i) | ||
84 | : "cc"); | ||
85 | |||
86 | return temp; | ||
87 | } | ||
88 | |||
89 | static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr) | ||
90 | { | ||
91 | unsigned int temp; | ||
92 | |||
93 | __asm__ __volatile__( | ||
94 | "1: llock %0, [%1] \n" | ||
95 | " bic %0, %0, %2 \n" | ||
96 | " scond %0, [%1] \n" | ||
97 | " bnz 1b \n" | ||
98 | : "=&r"(temp) | ||
99 | : "r"(addr), "ir"(mask) | ||
100 | : "cc"); | ||
101 | } | 58 | } |
102 | 59 | ||
103 | #else /* !CONFIG_ARC_HAS_LLSC */ | 60 | #else /* !CONFIG_ARC_HAS_LLSC */ |
@@ -126,6 +83,7 @@ static inline void atomic_set(atomic_t *v, int i) | |||
126 | v->counter = i; | 83 | v->counter = i; |
127 | atomic_ops_unlock(flags); | 84 | atomic_ops_unlock(flags); |
128 | } | 85 | } |
86 | |||
129 | #endif | 87 | #endif |
130 | 88 | ||
131 | /* | 89 | /* |
@@ -133,62 +91,46 @@ static inline void atomic_set(atomic_t *v, int i) | |||
133 | * Locking would change to irq-disabling only (UP) and spinlocks (SMP) | 91 | * Locking would change to irq-disabling only (UP) and spinlocks (SMP) |
134 | */ | 92 | */ |
135 | 93 | ||
136 | static inline void atomic_add(int i, atomic_t *v) | 94 | #define ATOMIC_OP(op, c_op, asm_op) \ |
137 | { | 95 | static inline void atomic_##op(int i, atomic_t *v) \ |
138 | unsigned long flags; | 96 | { \ |
139 | 97 | unsigned long flags; \ | |
140 | atomic_ops_lock(flags); | 98 | \ |
141 | v->counter += i; | 99 | atomic_ops_lock(flags); \ |
142 | atomic_ops_unlock(flags); | 100 | v->counter c_op i; \ |
101 | atomic_ops_unlock(flags); \ | ||
143 | } | 102 | } |
144 | 103 | ||
145 | static inline void atomic_sub(int i, atomic_t *v) | 104 | #define ATOMIC_OP_RETURN(op, c_op) \ |
146 | { | 105 | static inline int atomic_##op##_return(int i, atomic_t *v) \ |
147 | unsigned long flags; | 106 | { \ |
148 | 107 | unsigned long flags; \ | |
149 | atomic_ops_lock(flags); | 108 | unsigned long temp; \ |
150 | v->counter -= i; | 109 | \ |
151 | atomic_ops_unlock(flags); | 110 | atomic_ops_lock(flags); \ |
111 | temp = v->counter; \ | ||
112 | temp c_op i; \ | ||
113 | v->counter = temp; \ | ||
114 | atomic_ops_unlock(flags); \ | ||
115 | \ | ||
116 | return temp; \ | ||
152 | } | 117 | } |
153 | 118 | ||
154 | static inline int atomic_add_return(int i, atomic_t *v) | 119 | #endif /* !CONFIG_ARC_HAS_LLSC */ |
155 | { | ||
156 | unsigned long flags; | ||
157 | unsigned long temp; | ||
158 | |||
159 | atomic_ops_lock(flags); | ||
160 | temp = v->counter; | ||
161 | temp += i; | ||
162 | v->counter = temp; | ||
163 | atomic_ops_unlock(flags); | ||
164 | |||
165 | return temp; | ||
166 | } | ||
167 | |||
168 | static inline int atomic_sub_return(int i, atomic_t *v) | ||
169 | { | ||
170 | unsigned long flags; | ||
171 | unsigned long temp; | ||
172 | |||
173 | atomic_ops_lock(flags); | ||
174 | temp = v->counter; | ||
175 | temp -= i; | ||
176 | v->counter = temp; | ||
177 | atomic_ops_unlock(flags); | ||
178 | 120 | ||
179 | return temp; | 121 | #define ATOMIC_OPS(op, c_op, asm_op) \ |
180 | } | 122 | ATOMIC_OP(op, c_op, asm_op) \ |
123 | ATOMIC_OP_RETURN(op, c_op, asm_op) | ||
181 | 124 | ||
182 | static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr) | 125 | ATOMIC_OPS(add, +=, add) |
183 | { | 126 | ATOMIC_OPS(sub, -=, sub) |
184 | unsigned long flags; | 127 | ATOMIC_OP(and, &=, and) |
185 | 128 | ||
186 | atomic_ops_lock(flags); | 129 | #define atomic_clear_mask(mask, v) atomic_and(~(mask), (v)) |
187 | *addr &= ~mask; | ||
188 | atomic_ops_unlock(flags); | ||
189 | } | ||
190 | 130 | ||
191 | #endif /* !CONFIG_ARC_HAS_LLSC */ | 131 | #undef ATOMIC_OPS |
132 | #undef ATOMIC_OP_RETURN | ||
133 | #undef ATOMIC_OP | ||
192 | 134 | ||
193 | /** | 135 | /** |
194 | * __atomic_add_unless - add unless the number is a given value | 136 | * __atomic_add_unless - add unless the number is a given value |
diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h index 3040359094d9..e22c11970b7b 100644 --- a/arch/arm/include/asm/atomic.h +++ b/arch/arm/include/asm/atomic.h | |||
@@ -27,7 +27,7 @@ | |||
27 | * strex/ldrex monitor on some implementations. The reason we can use it for | 27 | * strex/ldrex monitor on some implementations. The reason we can use it for |
28 | * atomic_set() is the clrex or dummy strex done on every exception return. | 28 | * atomic_set() is the clrex or dummy strex done on every exception return. |
29 | */ | 29 | */ |
30 | #define atomic_read(v) (*(volatile int *)&(v)->counter) | 30 | #define atomic_read(v) ACCESS_ONCE((v)->counter) |
31 | #define atomic_set(v,i) (((v)->counter) = (i)) | 31 | #define atomic_set(v,i) (((v)->counter) = (i)) |
32 | 32 | ||
33 | #if __LINUX_ARM_ARCH__ >= 6 | 33 | #if __LINUX_ARM_ARCH__ >= 6 |
@@ -37,84 +37,47 @@ | |||
37 | * store exclusive to ensure that these are atomic. We may loop | 37 | * store exclusive to ensure that these are atomic. We may loop |
38 | * to ensure that the update happens. | 38 | * to ensure that the update happens. |
39 | */ | 39 | */ |
40 | static inline void atomic_add(int i, atomic_t *v) | ||
41 | { | ||
42 | unsigned long tmp; | ||
43 | int result; | ||
44 | |||
45 | prefetchw(&v->counter); | ||
46 | __asm__ __volatile__("@ atomic_add\n" | ||
47 | "1: ldrex %0, [%3]\n" | ||
48 | " add %0, %0, %4\n" | ||
49 | " strex %1, %0, [%3]\n" | ||
50 | " teq %1, #0\n" | ||
51 | " bne 1b" | ||
52 | : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) | ||
53 | : "r" (&v->counter), "Ir" (i) | ||
54 | : "cc"); | ||
55 | } | ||
56 | 40 | ||
57 | static inline int atomic_add_return(int i, atomic_t *v) | 41 | #define ATOMIC_OP(op, c_op, asm_op) \ |
58 | { | 42 | static inline void atomic_##op(int i, atomic_t *v) \ |
59 | unsigned long tmp; | 43 | { \ |
60 | int result; | 44 | unsigned long tmp; \ |
61 | 45 | int result; \ | |
62 | smp_mb(); | 46 | \ |
63 | prefetchw(&v->counter); | 47 | prefetchw(&v->counter); \ |
64 | 48 | __asm__ __volatile__("@ atomic_" #op "\n" \ | |
65 | __asm__ __volatile__("@ atomic_add_return\n" | 49 | "1: ldrex %0, [%3]\n" \ |
66 | "1: ldrex %0, [%3]\n" | 50 | " " #asm_op " %0, %0, %4\n" \ |
67 | " add %0, %0, %4\n" | 51 | " strex %1, %0, [%3]\n" \ |
68 | " strex %1, %0, [%3]\n" | 52 | " teq %1, #0\n" \ |
69 | " teq %1, #0\n" | 53 | " bne 1b" \ |
70 | " bne 1b" | 54 | : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) \ |
71 | : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) | 55 | : "r" (&v->counter), "Ir" (i) \ |
72 | : "r" (&v->counter), "Ir" (i) | 56 | : "cc"); \ |
73 | : "cc"); | 57 | } \ |
74 | 58 | ||
75 | smp_mb(); | 59 | #define ATOMIC_OP_RETURN(op, c_op, asm_op) \ |
76 | 60 | static inline int atomic_##op##_return(int i, atomic_t *v) \ | |
77 | return result; | 61 | { \ |
78 | } | 62 | unsigned long tmp; \ |
79 | 63 | int result; \ | |
80 | static inline void atomic_sub(int i, atomic_t *v) | 64 | \ |
81 | { | 65 | smp_mb(); \ |
82 | unsigned long tmp; | 66 | prefetchw(&v->counter); \ |
83 | int result; | 67 | \ |
84 | 68 | __asm__ __volatile__("@ atomic_" #op "_return\n" \ | |
85 | prefetchw(&v->counter); | 69 | "1: ldrex %0, [%3]\n" \ |
86 | __asm__ __volatile__("@ atomic_sub\n" | 70 | " " #asm_op " %0, %0, %4\n" \ |
87 | "1: ldrex %0, [%3]\n" | 71 | " strex %1, %0, [%3]\n" \ |
88 | " sub %0, %0, %4\n" | 72 | " teq %1, #0\n" \ |
89 | " strex %1, %0, [%3]\n" | 73 | " bne 1b" \ |
90 | " teq %1, #0\n" | 74 | : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) \ |
91 | " bne 1b" | 75 | : "r" (&v->counter), "Ir" (i) \ |
92 | : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) | 76 | : "cc"); \ |
93 | : "r" (&v->counter), "Ir" (i) | 77 | \ |
94 | : "cc"); | 78 | smp_mb(); \ |
95 | } | 79 | \ |
96 | 80 | return result; \ | |
97 | static inline int atomic_sub_return(int i, atomic_t *v) | ||
98 | { | ||
99 | unsigned long tmp; | ||
100 | int result; | ||
101 | |||
102 | smp_mb(); | ||
103 | prefetchw(&v->counter); | ||
104 | |||
105 | __asm__ __volatile__("@ atomic_sub_return\n" | ||
106 | "1: ldrex %0, [%3]\n" | ||
107 | " sub %0, %0, %4\n" | ||
108 | " strex %1, %0, [%3]\n" | ||
109 | " teq %1, #0\n" | ||
110 | " bne 1b" | ||
111 | : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) | ||
112 | : "r" (&v->counter), "Ir" (i) | ||
113 | : "cc"); | ||
114 | |||
115 | smp_mb(); | ||
116 | |||
117 | return result; | ||
118 | } | 81 | } |
119 | 82 | ||
120 | static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new) | 83 | static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new) |
@@ -174,33 +137,29 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) | |||
174 | #error SMP not supported on pre-ARMv6 CPUs | 137 | #error SMP not supported on pre-ARMv6 CPUs |
175 | #endif | 138 | #endif |
176 | 139 | ||
177 | static inline int atomic_add_return(int i, atomic_t *v) | 140 | #define ATOMIC_OP(op, c_op, asm_op) \ |
178 | { | 141 | static inline void atomic_##op(int i, atomic_t *v) \ |
179 | unsigned long flags; | 142 | { \ |
180 | int val; | 143 | unsigned long flags; \ |
181 | 144 | \ | |
182 | raw_local_irq_save(flags); | 145 | raw_local_irq_save(flags); \ |
183 | val = v->counter; | 146 | v->counter c_op i; \ |
184 | v->counter = val += i; | 147 | raw_local_irq_restore(flags); \ |
185 | raw_local_irq_restore(flags); | 148 | } \ |
186 | 149 | ||
187 | return val; | 150 | #define ATOMIC_OP_RETURN(op, c_op, asm_op) \ |
188 | } | 151 | static inline int atomic_##op##_return(int i, atomic_t *v) \ |
189 | #define atomic_add(i, v) (void) atomic_add_return(i, v) | 152 | { \ |
190 | 153 | unsigned long flags; \ | |
191 | static inline int atomic_sub_return(int i, atomic_t *v) | 154 | int val; \ |
192 | { | 155 | \ |
193 | unsigned long flags; | 156 | raw_local_irq_save(flags); \ |
194 | int val; | 157 | v->counter c_op i; \ |
195 | 158 | val = v->counter; \ | |
196 | raw_local_irq_save(flags); | 159 | raw_local_irq_restore(flags); \ |
197 | val = v->counter; | 160 | \ |
198 | v->counter = val -= i; | 161 | return val; \ |
199 | raw_local_irq_restore(flags); | ||
200 | |||
201 | return val; | ||
202 | } | 162 | } |
203 | #define atomic_sub(i, v) (void) atomic_sub_return(i, v) | ||
204 | 163 | ||
205 | static inline int atomic_cmpxchg(atomic_t *v, int old, int new) | 164 | static inline int atomic_cmpxchg(atomic_t *v, int old, int new) |
206 | { | 165 | { |
@@ -228,6 +187,17 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) | |||
228 | 187 | ||
229 | #endif /* __LINUX_ARM_ARCH__ */ | 188 | #endif /* __LINUX_ARM_ARCH__ */ |
230 | 189 | ||
190 | #define ATOMIC_OPS(op, c_op, asm_op) \ | ||
191 | ATOMIC_OP(op, c_op, asm_op) \ | ||
192 | ATOMIC_OP_RETURN(op, c_op, asm_op) | ||
193 | |||
194 | ATOMIC_OPS(add, +=, add) | ||
195 | ATOMIC_OPS(sub, -=, sub) | ||
196 | |||
197 | #undef ATOMIC_OPS | ||
198 | #undef ATOMIC_OP_RETURN | ||
199 | #undef ATOMIC_OP | ||
200 | |||
231 | #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) | 201 | #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) |
232 | 202 | ||
233 | #define atomic_inc(v) atomic_add(1, v) | 203 | #define atomic_inc(v) atomic_add(1, v) |
@@ -300,89 +270,60 @@ static inline void atomic64_set(atomic64_t *v, long long i) | |||
300 | } | 270 | } |
301 | #endif | 271 | #endif |
302 | 272 | ||
303 | static inline void atomic64_add(long long i, atomic64_t *v) | 273 | #define ATOMIC64_OP(op, op1, op2) \ |
304 | { | 274 | static inline void atomic64_##op(long long i, atomic64_t *v) \ |
305 | long long result; | 275 | { \ |
306 | unsigned long tmp; | 276 | long long result; \ |
307 | 277 | unsigned long tmp; \ | |
308 | prefetchw(&v->counter); | 278 | \ |
309 | __asm__ __volatile__("@ atomic64_add\n" | 279 | prefetchw(&v->counter); \ |
310 | "1: ldrexd %0, %H0, [%3]\n" | 280 | __asm__ __volatile__("@ atomic64_" #op "\n" \ |
311 | " adds %Q0, %Q0, %Q4\n" | 281 | "1: ldrexd %0, %H0, [%3]\n" \ |
312 | " adc %R0, %R0, %R4\n" | 282 | " " #op1 " %Q0, %Q0, %Q4\n" \ |
313 | " strexd %1, %0, %H0, [%3]\n" | 283 | " " #op2 " %R0, %R0, %R4\n" \ |
314 | " teq %1, #0\n" | 284 | " strexd %1, %0, %H0, [%3]\n" \ |
315 | " bne 1b" | 285 | " teq %1, #0\n" \ |
316 | : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) | 286 | " bne 1b" \ |
317 | : "r" (&v->counter), "r" (i) | 287 | : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) \ |
318 | : "cc"); | 288 | : "r" (&v->counter), "r" (i) \ |
319 | } | 289 | : "cc"); \ |
320 | 290 | } \ | |
321 | static inline long long atomic64_add_return(long long i, atomic64_t *v) | 291 | |
322 | { | 292 | #define ATOMIC64_OP_RETURN(op, op1, op2) \ |
323 | long long result; | 293 | static inline long long atomic64_##op##_return(long long i, atomic64_t *v) \ |
324 | unsigned long tmp; | 294 | { \ |
325 | 295 | long long result; \ | |
326 | smp_mb(); | 296 | unsigned long tmp; \ |
327 | prefetchw(&v->counter); | 297 | \ |
328 | 298 | smp_mb(); \ | |
329 | __asm__ __volatile__("@ atomic64_add_return\n" | 299 | prefetchw(&v->counter); \ |
330 | "1: ldrexd %0, %H0, [%3]\n" | 300 | \ |
331 | " adds %Q0, %Q0, %Q4\n" | 301 | __asm__ __volatile__("@ atomic64_" #op "_return\n" \ |
332 | " adc %R0, %R0, %R4\n" | 302 | "1: ldrexd %0, %H0, [%3]\n" \ |
333 | " strexd %1, %0, %H0, [%3]\n" | 303 | " " #op1 " %Q0, %Q0, %Q4\n" \ |
334 | " teq %1, #0\n" | 304 | " " #op2 " %R0, %R0, %R4\n" \ |
335 | " bne 1b" | 305 | " strexd %1, %0, %H0, [%3]\n" \ |
336 | : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) | 306 | " teq %1, #0\n" \ |
337 | : "r" (&v->counter), "r" (i) | 307 | " bne 1b" \ |
338 | : "cc"); | 308 | : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) \ |
339 | 309 | : "r" (&v->counter), "r" (i) \ | |
340 | smp_mb(); | 310 | : "cc"); \ |
341 | 311 | \ | |
342 | return result; | 312 | smp_mb(); \ |
343 | } | 313 | \ |
344 | 314 | return result; \ | |
345 | static inline void atomic64_sub(long long i, atomic64_t *v) | ||
346 | { | ||
347 | long long result; | ||
348 | unsigned long tmp; | ||
349 | |||
350 | prefetchw(&v->counter); | ||
351 | __asm__ __volatile__("@ atomic64_sub\n" | ||
352 | "1: ldrexd %0, %H0, [%3]\n" | ||
353 | " subs %Q0, %Q0, %Q4\n" | ||
354 | " sbc %R0, %R0, %R4\n" | ||
355 | " strexd %1, %0, %H0, [%3]\n" | ||
356 | " teq %1, #0\n" | ||
357 | " bne 1b" | ||
358 | : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) | ||
359 | : "r" (&v->counter), "r" (i) | ||
360 | : "cc"); | ||
361 | } | 315 | } |
362 | 316 | ||
363 | static inline long long atomic64_sub_return(long long i, atomic64_t *v) | 317 | #define ATOMIC64_OPS(op, op1, op2) \ |
364 | { | 318 | ATOMIC64_OP(op, op1, op2) \ |
365 | long long result; | 319 | ATOMIC64_OP_RETURN(op, op1, op2) |
366 | unsigned long tmp; | ||
367 | |||
368 | smp_mb(); | ||
369 | prefetchw(&v->counter); | ||
370 | |||
371 | __asm__ __volatile__("@ atomic64_sub_return\n" | ||
372 | "1: ldrexd %0, %H0, [%3]\n" | ||
373 | " subs %Q0, %Q0, %Q4\n" | ||
374 | " sbc %R0, %R0, %R4\n" | ||
375 | " strexd %1, %0, %H0, [%3]\n" | ||
376 | " teq %1, #0\n" | ||
377 | " bne 1b" | ||
378 | : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) | ||
379 | : "r" (&v->counter), "r" (i) | ||
380 | : "cc"); | ||
381 | 320 | ||
382 | smp_mb(); | 321 | ATOMIC64_OPS(add, adds, adc) |
322 | ATOMIC64_OPS(sub, subs, sbc) | ||
383 | 323 | ||
384 | return result; | 324 | #undef ATOMIC64_OPS |
385 | } | 325 | #undef ATOMIC64_OP_RETURN |
326 | #undef ATOMIC64_OP | ||
386 | 327 | ||
387 | static inline long long atomic64_cmpxchg(atomic64_t *ptr, long long old, | 328 | static inline long long atomic64_cmpxchg(atomic64_t *ptr, long long old, |
388 | long long new) | 329 | long long new) |
diff --git a/arch/arm64/include/asm/atomic.h b/arch/arm64/include/asm/atomic.h index 65f1569ac96e..7047051ded40 100644 --- a/arch/arm64/include/asm/atomic.h +++ b/arch/arm64/include/asm/atomic.h | |||
@@ -35,7 +35,7 @@ | |||
35 | * strex/ldrex monitor on some implementations. The reason we can use it for | 35 | * strex/ldrex monitor on some implementations. The reason we can use it for |
36 | * atomic_set() is the clrex or dummy strex done on every exception return. | 36 | * atomic_set() is the clrex or dummy strex done on every exception return. |
37 | */ | 37 | */ |
38 | #define atomic_read(v) (*(volatile int *)&(v)->counter) | 38 | #define atomic_read(v) ACCESS_ONCE((v)->counter) |
39 | #define atomic_set(v,i) (((v)->counter) = (i)) | 39 | #define atomic_set(v,i) (((v)->counter) = (i)) |
40 | 40 | ||
41 | /* | 41 | /* |
@@ -43,69 +43,51 @@ | |||
43 | * store exclusive to ensure that these are atomic. We may loop | 43 | * store exclusive to ensure that these are atomic. We may loop |
44 | * to ensure that the update happens. | 44 | * to ensure that the update happens. |
45 | */ | 45 | */ |
46 | static inline void atomic_add(int i, atomic_t *v) | ||
47 | { | ||
48 | unsigned long tmp; | ||
49 | int result; | ||
50 | |||
51 | asm volatile("// atomic_add\n" | ||
52 | "1: ldxr %w0, %2\n" | ||
53 | " add %w0, %w0, %w3\n" | ||
54 | " stxr %w1, %w0, %2\n" | ||
55 | " cbnz %w1, 1b" | ||
56 | : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) | ||
57 | : "Ir" (i)); | ||
58 | } | ||
59 | |||
60 | static inline int atomic_add_return(int i, atomic_t *v) | ||
61 | { | ||
62 | unsigned long tmp; | ||
63 | int result; | ||
64 | |||
65 | asm volatile("// atomic_add_return\n" | ||
66 | "1: ldxr %w0, %2\n" | ||
67 | " add %w0, %w0, %w3\n" | ||
68 | " stlxr %w1, %w0, %2\n" | ||
69 | " cbnz %w1, 1b" | ||
70 | : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) | ||
71 | : "Ir" (i) | ||
72 | : "memory"); | ||
73 | |||
74 | smp_mb(); | ||
75 | return result; | ||
76 | } | ||
77 | |||
78 | static inline void atomic_sub(int i, atomic_t *v) | ||
79 | { | ||
80 | unsigned long tmp; | ||
81 | int result; | ||
82 | 46 | ||
83 | asm volatile("// atomic_sub\n" | 47 | #define ATOMIC_OP(op, asm_op) \ |
84 | "1: ldxr %w0, %2\n" | 48 | static inline void atomic_##op(int i, atomic_t *v) \ |
85 | " sub %w0, %w0, %w3\n" | 49 | { \ |
86 | " stxr %w1, %w0, %2\n" | 50 | unsigned long tmp; \ |
87 | " cbnz %w1, 1b" | 51 | int result; \ |
88 | : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) | 52 | \ |
89 | : "Ir" (i)); | 53 | asm volatile("// atomic_" #op "\n" \ |
54 | "1: ldxr %w0, %2\n" \ | ||
55 | " " #asm_op " %w0, %w0, %w3\n" \ | ||
56 | " stxr %w1, %w0, %2\n" \ | ||
57 | " cbnz %w1, 1b" \ | ||
58 | : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) \ | ||
59 | : "Ir" (i)); \ | ||
60 | } \ | ||
61 | |||
62 | #define ATOMIC_OP_RETURN(op, asm_op) \ | ||
63 | static inline int atomic_##op##_return(int i, atomic_t *v) \ | ||
64 | { \ | ||
65 | unsigned long tmp; \ | ||
66 | int result; \ | ||
67 | \ | ||
68 | asm volatile("// atomic_" #op "_return\n" \ | ||
69 | "1: ldxr %w0, %2\n" \ | ||
70 | " " #asm_op " %w0, %w0, %w3\n" \ | ||
71 | " stlxr %w1, %w0, %2\n" \ | ||
72 | " cbnz %w1, 1b" \ | ||
73 | : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) \ | ||
74 | : "Ir" (i) \ | ||
75 | : "memory"); \ | ||
76 | \ | ||
77 | smp_mb(); \ | ||
78 | return result; \ | ||
90 | } | 79 | } |
91 | 80 | ||
92 | static inline int atomic_sub_return(int i, atomic_t *v) | 81 | #define ATOMIC_OPS(op, asm_op) \ |
93 | { | 82 | ATOMIC_OP(op, asm_op) \ |
94 | unsigned long tmp; | 83 | ATOMIC_OP_RETURN(op, asm_op) |
95 | int result; | ||
96 | 84 | ||
97 | asm volatile("// atomic_sub_return\n" | 85 | ATOMIC_OPS(add, add) |
98 | "1: ldxr %w0, %2\n" | 86 | ATOMIC_OPS(sub, sub) |
99 | " sub %w0, %w0, %w3\n" | ||
100 | " stlxr %w1, %w0, %2\n" | ||
101 | " cbnz %w1, 1b" | ||
102 | : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) | ||
103 | : "Ir" (i) | ||
104 | : "memory"); | ||
105 | 87 | ||
106 | smp_mb(); | 88 | #undef ATOMIC_OPS |
107 | return result; | 89 | #undef ATOMIC_OP_RETURN |
108 | } | 90 | #undef ATOMIC_OP |
109 | 91 | ||
110 | static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new) | 92 | static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new) |
111 | { | 93 | { |
@@ -157,72 +139,53 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) | |||
157 | */ | 139 | */ |
158 | #define ATOMIC64_INIT(i) { (i) } | 140 | #define ATOMIC64_INIT(i) { (i) } |
159 | 141 | ||
160 | #define atomic64_read(v) (*(volatile long *)&(v)->counter) | 142 | #define atomic64_read(v) ACCESS_ONCE((v)->counter) |
161 | #define atomic64_set(v,i) (((v)->counter) = (i)) | 143 | #define atomic64_set(v,i) (((v)->counter) = (i)) |
162 | 144 | ||
163 | static inline void atomic64_add(u64 i, atomic64_t *v) | 145 | #define ATOMIC64_OP(op, asm_op) \ |
164 | { | 146 | static inline void atomic64_##op(long i, atomic64_t *v) \ |
165 | long result; | 147 | { \ |
166 | unsigned long tmp; | 148 | long result; \ |
167 | 149 | unsigned long tmp; \ | |
168 | asm volatile("// atomic64_add\n" | 150 | \ |
169 | "1: ldxr %0, %2\n" | 151 | asm volatile("// atomic64_" #op "\n" \ |
170 | " add %0, %0, %3\n" | 152 | "1: ldxr %0, %2\n" \ |
171 | " stxr %w1, %0, %2\n" | 153 | " " #asm_op " %0, %0, %3\n" \ |
172 | " cbnz %w1, 1b" | 154 | " stxr %w1, %0, %2\n" \ |
173 | : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) | 155 | " cbnz %w1, 1b" \ |
174 | : "Ir" (i)); | 156 | : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) \ |
157 | : "Ir" (i)); \ | ||
158 | } \ | ||
159 | |||
160 | #define ATOMIC64_OP_RETURN(op, asm_op) \ | ||
161 | static inline long atomic64_##op##_return(long i, atomic64_t *v) \ | ||
162 | { \ | ||
163 | long result; \ | ||
164 | unsigned long tmp; \ | ||
165 | \ | ||
166 | asm volatile("// atomic64_" #op "_return\n" \ | ||
167 | "1: ldxr %0, %2\n" \ | ||
168 | " " #asm_op " %0, %0, %3\n" \ | ||
169 | " stlxr %w1, %0, %2\n" \ | ||
170 | " cbnz %w1, 1b" \ | ||
171 | : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) \ | ||
172 | : "Ir" (i) \ | ||
173 | : "memory"); \ | ||
174 | \ | ||
175 | smp_mb(); \ | ||
176 | return result; \ | ||
175 | } | 177 | } |
176 | 178 | ||
177 | static inline long atomic64_add_return(long i, atomic64_t *v) | 179 | #define ATOMIC64_OPS(op, asm_op) \ |
178 | { | 180 | ATOMIC64_OP(op, asm_op) \ |
179 | long result; | 181 | ATOMIC64_OP_RETURN(op, asm_op) |
180 | unsigned long tmp; | ||
181 | 182 | ||
182 | asm volatile("// atomic64_add_return\n" | 183 | ATOMIC64_OPS(add, add) |
183 | "1: ldxr %0, %2\n" | 184 | ATOMIC64_OPS(sub, sub) |
184 | " add %0, %0, %3\n" | ||
185 | " stlxr %w1, %0, %2\n" | ||
186 | " cbnz %w1, 1b" | ||
187 | : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) | ||
188 | : "Ir" (i) | ||
189 | : "memory"); | ||
190 | 185 | ||
191 | smp_mb(); | 186 | #undef ATOMIC64_OPS |
192 | return result; | 187 | #undef ATOMIC64_OP_RETURN |
193 | } | 188 | #undef ATOMIC64_OP |
194 | |||
195 | static inline void atomic64_sub(u64 i, atomic64_t *v) | ||
196 | { | ||
197 | long result; | ||
198 | unsigned long tmp; | ||
199 | |||
200 | asm volatile("// atomic64_sub\n" | ||
201 | "1: ldxr %0, %2\n" | ||
202 | " sub %0, %0, %3\n" | ||
203 | " stxr %w1, %0, %2\n" | ||
204 | " cbnz %w1, 1b" | ||
205 | : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) | ||
206 | : "Ir" (i)); | ||
207 | } | ||
208 | |||
209 | static inline long atomic64_sub_return(long i, atomic64_t *v) | ||
210 | { | ||
211 | long result; | ||
212 | unsigned long tmp; | ||
213 | |||
214 | asm volatile("// atomic64_sub_return\n" | ||
215 | "1: ldxr %0, %2\n" | ||
216 | " sub %0, %0, %3\n" | ||
217 | " stlxr %w1, %0, %2\n" | ||
218 | " cbnz %w1, 1b" | ||
219 | : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) | ||
220 | : "Ir" (i) | ||
221 | : "memory"); | ||
222 | |||
223 | smp_mb(); | ||
224 | return result; | ||
225 | } | ||
226 | 189 | ||
227 | static inline long atomic64_cmpxchg(atomic64_t *ptr, long old, long new) | 190 | static inline long atomic64_cmpxchg(atomic64_t *ptr, long old, long new) |
228 | { | 191 | { |
diff --git a/arch/avr32/include/asm/atomic.h b/arch/avr32/include/asm/atomic.h index 0780f3f2415b..2d07ce1c5327 100644 --- a/arch/avr32/include/asm/atomic.h +++ b/arch/avr32/include/asm/atomic.h | |||
@@ -19,33 +19,46 @@ | |||
19 | 19 | ||
20 | #define ATOMIC_INIT(i) { (i) } | 20 | #define ATOMIC_INIT(i) { (i) } |
21 | 21 | ||
22 | #define atomic_read(v) (*(volatile int *)&(v)->counter) | 22 | #define atomic_read(v) ACCESS_ONCE((v)->counter) |
23 | #define atomic_set(v, i) (((v)->counter) = i) | 23 | #define atomic_set(v, i) (((v)->counter) = i) |
24 | 24 | ||
25 | #define ATOMIC_OP_RETURN(op, asm_op, asm_con) \ | ||
26 | static inline int __atomic_##op##_return(int i, atomic_t *v) \ | ||
27 | { \ | ||
28 | int result; \ | ||
29 | \ | ||
30 | asm volatile( \ | ||
31 | "/* atomic_" #op "_return */\n" \ | ||
32 | "1: ssrf 5\n" \ | ||
33 | " ld.w %0, %2\n" \ | ||
34 | " " #asm_op " %0, %3\n" \ | ||
35 | " stcond %1, %0\n" \ | ||
36 | " brne 1b" \ | ||
37 | : "=&r" (result), "=o" (v->counter) \ | ||
38 | : "m" (v->counter), #asm_con (i) \ | ||
39 | : "cc"); \ | ||
40 | \ | ||
41 | return result; \ | ||
42 | } | ||
43 | |||
44 | ATOMIC_OP_RETURN(sub, sub, rKs21) | ||
45 | ATOMIC_OP_RETURN(add, add, r) | ||
46 | |||
47 | #undef ATOMIC_OP_RETURN | ||
48 | |||
25 | /* | 49 | /* |
26 | * atomic_sub_return - subtract the atomic variable | 50 | * Probably found the reason why we want to use sub with the signed 21-bit |
27 | * @i: integer value to subtract | 51 | * limit, it uses one less register than the add instruction that can add up to |
28 | * @v: pointer of type atomic_t | 52 | * 32-bit values. |
29 | * | 53 | * |
30 | * Atomically subtracts @i from @v. Returns the resulting value. | 54 | * Both instructions are 32-bit, to use a 16-bit instruction the immediate is |
55 | * very small; 4 bit. | ||
56 | * | ||
57 | * sub 32-bit, type IV, takes a register and subtracts a 21-bit immediate. | ||
58 | * add 32-bit, type II, adds two register values together. | ||
31 | */ | 59 | */ |
32 | static inline int atomic_sub_return(int i, atomic_t *v) | 60 | #define IS_21BIT_CONST(i) \ |
33 | { | 61 | (__builtin_constant_p(i) && ((i) >= -1048575) && ((i) <= 1048576)) |
34 | int result; | ||
35 | |||
36 | asm volatile( | ||
37 | "/* atomic_sub_return */\n" | ||
38 | "1: ssrf 5\n" | ||
39 | " ld.w %0, %2\n" | ||
40 | " sub %0, %3\n" | ||
41 | " stcond %1, %0\n" | ||
42 | " brne 1b" | ||
43 | : "=&r"(result), "=o"(v->counter) | ||
44 | : "m"(v->counter), "rKs21"(i) | ||
45 | : "cc"); | ||
46 | |||
47 | return result; | ||
48 | } | ||
49 | 62 | ||
50 | /* | 63 | /* |
51 | * atomic_add_return - add integer to atomic variable | 64 | * atomic_add_return - add integer to atomic variable |
@@ -56,51 +69,25 @@ static inline int atomic_sub_return(int i, atomic_t *v) | |||
56 | */ | 69 | */ |
57 | static inline int atomic_add_return(int i, atomic_t *v) | 70 | static inline int atomic_add_return(int i, atomic_t *v) |
58 | { | 71 | { |
59 | int result; | 72 | if (IS_21BIT_CONST(i)) |
60 | 73 | return __atomic_sub_return(-i, v); | |
61 | if (__builtin_constant_p(i) && (i >= -1048575) && (i <= 1048576)) | ||
62 | result = atomic_sub_return(-i, v); | ||
63 | else | ||
64 | asm volatile( | ||
65 | "/* atomic_add_return */\n" | ||
66 | "1: ssrf 5\n" | ||
67 | " ld.w %0, %1\n" | ||
68 | " add %0, %3\n" | ||
69 | " stcond %2, %0\n" | ||
70 | " brne 1b" | ||
71 | : "=&r"(result), "=o"(v->counter) | ||
72 | : "m"(v->counter), "r"(i) | ||
73 | : "cc", "memory"); | ||
74 | 74 | ||
75 | return result; | 75 | return __atomic_add_return(i, v); |
76 | } | 76 | } |
77 | 77 | ||
78 | /* | 78 | /* |
79 | * atomic_sub_unless - sub unless the number is a given value | 79 | * atomic_sub_return - subtract the atomic variable |
80 | * @i: integer value to subtract | ||
80 | * @v: pointer of type atomic_t | 81 | * @v: pointer of type atomic_t |
81 | * @a: the amount to subtract from v... | ||
82 | * @u: ...unless v is equal to u. | ||
83 | * | 82 | * |
84 | * Atomically subtract @a from @v, so long as it was not @u. | 83 | * Atomically subtracts @i from @v. Returns the resulting value. |
85 | * Returns the old value of @v. | 84 | */ |
86 | */ | 85 | static inline int atomic_sub_return(int i, atomic_t *v) |
87 | static inline void atomic_sub_unless(atomic_t *v, int a, int u) | ||
88 | { | 86 | { |
89 | int tmp; | 87 | if (IS_21BIT_CONST(i)) |
88 | return __atomic_sub_return(i, v); | ||
90 | 89 | ||
91 | asm volatile( | 90 | return __atomic_add_return(-i, v); |
92 | "/* atomic_sub_unless */\n" | ||
93 | "1: ssrf 5\n" | ||
94 | " ld.w %0, %2\n" | ||
95 | " cp.w %0, %4\n" | ||
96 | " breq 1f\n" | ||
97 | " sub %0, %3\n" | ||
98 | " stcond %1, %0\n" | ||
99 | " brne 1b\n" | ||
100 | "1:" | ||
101 | : "=&r"(tmp), "=o"(v->counter) | ||
102 | : "m"(v->counter), "rKs21"(a), "rKs21"(u) | ||
103 | : "cc", "memory"); | ||
104 | } | 91 | } |
105 | 92 | ||
106 | /* | 93 | /* |
@@ -116,9 +103,21 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) | |||
116 | { | 103 | { |
117 | int tmp, old = atomic_read(v); | 104 | int tmp, old = atomic_read(v); |
118 | 105 | ||
119 | if (__builtin_constant_p(a) && (a >= -1048575) && (a <= 1048576)) | 106 | if (IS_21BIT_CONST(a)) { |
120 | atomic_sub_unless(v, -a, u); | 107 | asm volatile( |
121 | else { | 108 | "/* __atomic_sub_unless */\n" |
109 | "1: ssrf 5\n" | ||
110 | " ld.w %0, %2\n" | ||
111 | " cp.w %0, %4\n" | ||
112 | " breq 1f\n" | ||
113 | " sub %0, %3\n" | ||
114 | " stcond %1, %0\n" | ||
115 | " brne 1b\n" | ||
116 | "1:" | ||
117 | : "=&r"(tmp), "=o"(v->counter) | ||
118 | : "m"(v->counter), "rKs21"(-a), "rKs21"(u) | ||
119 | : "cc", "memory"); | ||
120 | } else { | ||
122 | asm volatile( | 121 | asm volatile( |
123 | "/* __atomic_add_unless */\n" | 122 | "/* __atomic_add_unless */\n" |
124 | "1: ssrf 5\n" | 123 | "1: ssrf 5\n" |
@@ -137,6 +136,8 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) | |||
137 | return old; | 136 | return old; |
138 | } | 137 | } |
139 | 138 | ||
139 | #undef IS_21BIT_CONST | ||
140 | |||
140 | /* | 141 | /* |
141 | * atomic_sub_if_positive - conditionally subtract integer from atomic variable | 142 | * atomic_sub_if_positive - conditionally subtract integer from atomic variable |
142 | * @i: integer value to subtract | 143 | * @i: integer value to subtract |
diff --git a/arch/cris/include/asm/atomic.h b/arch/cris/include/asm/atomic.h index aa429baebaf9..279766a70664 100644 --- a/arch/cris/include/asm/atomic.h +++ b/arch/cris/include/asm/atomic.h | |||
@@ -17,48 +17,41 @@ | |||
17 | 17 | ||
18 | #define ATOMIC_INIT(i) { (i) } | 18 | #define ATOMIC_INIT(i) { (i) } |
19 | 19 | ||
20 | #define atomic_read(v) (*(volatile int *)&(v)->counter) | 20 | #define atomic_read(v) ACCESS_ONCE((v)->counter) |
21 | #define atomic_set(v,i) (((v)->counter) = (i)) | 21 | #define atomic_set(v,i) (((v)->counter) = (i)) |
22 | 22 | ||
23 | /* These should be written in asm but we do it in C for now. */ | 23 | /* These should be written in asm but we do it in C for now. */ |
24 | 24 | ||
25 | static inline void atomic_add(int i, volatile atomic_t *v) | 25 | #define ATOMIC_OP(op, c_op) \ |
26 | { | 26 | static inline void atomic_##op(int i, volatile atomic_t *v) \ |
27 | unsigned long flags; | 27 | { \ |
28 | cris_atomic_save(v, flags); | 28 | unsigned long flags; \ |
29 | v->counter += i; | 29 | cris_atomic_save(v, flags); \ |
30 | cris_atomic_restore(v, flags); | 30 | v->counter c_op i; \ |
31 | cris_atomic_restore(v, flags); \ | ||
32 | } \ | ||
33 | |||
34 | #define ATOMIC_OP_RETURN(op, c_op) \ | ||
35 | static inline int atomic_##op##_return(int i, volatile atomic_t *v) \ | ||
36 | { \ | ||
37 | unsigned long flags; \ | ||
38 | int retval; \ | ||
39 | cris_atomic_save(v, flags); \ | ||
40 | retval = (v->counter c_op i); \ | ||
41 | cris_atomic_restore(v, flags); \ | ||
42 | return retval; \ | ||
31 | } | 43 | } |
32 | 44 | ||
33 | static inline void atomic_sub(int i, volatile atomic_t *v) | 45 | #define ATOMIC_OPS(op, c_op) ATOMIC_OP(op, c_op) ATOMIC_OP_RETURN(op, c_op) |
34 | { | ||
35 | unsigned long flags; | ||
36 | cris_atomic_save(v, flags); | ||
37 | v->counter -= i; | ||
38 | cris_atomic_restore(v, flags); | ||
39 | } | ||
40 | 46 | ||
41 | static inline int atomic_add_return(int i, volatile atomic_t *v) | 47 | ATOMIC_OPS(add, +=) |
42 | { | 48 | ATOMIC_OPS(sub, -=) |
43 | unsigned long flags; | ||
44 | int retval; | ||
45 | cris_atomic_save(v, flags); | ||
46 | retval = (v->counter += i); | ||
47 | cris_atomic_restore(v, flags); | ||
48 | return retval; | ||
49 | } | ||
50 | 49 | ||
51 | #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) | 50 | #undef ATOMIC_OPS |
51 | #undef ATOMIC_OP_RETURN | ||
52 | #undef ATOMIC_OP | ||
52 | 53 | ||
53 | static inline int atomic_sub_return(int i, volatile atomic_t *v) | 54 | #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) |
54 | { | ||
55 | unsigned long flags; | ||
56 | int retval; | ||
57 | cris_atomic_save(v, flags); | ||
58 | retval = (v->counter -= i); | ||
59 | cris_atomic_restore(v, flags); | ||
60 | return retval; | ||
61 | } | ||
62 | 55 | ||
63 | static inline int atomic_sub_and_test(int i, volatile atomic_t *v) | 56 | static inline int atomic_sub_and_test(int i, volatile atomic_t *v) |
64 | { | 57 | { |
diff --git a/arch/frv/include/asm/atomic.h b/arch/frv/include/asm/atomic.h index f6c3a1690101..102190a61d65 100644 --- a/arch/frv/include/asm/atomic.h +++ b/arch/frv/include/asm/atomic.h | |||
@@ -31,7 +31,7 @@ | |||
31 | */ | 31 | */ |
32 | 32 | ||
33 | #define ATOMIC_INIT(i) { (i) } | 33 | #define ATOMIC_INIT(i) { (i) } |
34 | #define atomic_read(v) (*(volatile int *)&(v)->counter) | 34 | #define atomic_read(v) ACCESS_ONCE((v)->counter) |
35 | #define atomic_set(v, i) (((v)->counter) = (i)) | 35 | #define atomic_set(v, i) (((v)->counter) = (i)) |
36 | 36 | ||
37 | #ifndef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS | 37 | #ifndef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS |
diff --git a/arch/hexagon/include/asm/atomic.h b/arch/hexagon/include/asm/atomic.h index de916b11bff5..93d07025f183 100644 --- a/arch/hexagon/include/asm/atomic.h +++ b/arch/hexagon/include/asm/atomic.h | |||
@@ -94,41 +94,47 @@ static inline int atomic_cmpxchg(atomic_t *v, int old, int new) | |||
94 | return __oldval; | 94 | return __oldval; |
95 | } | 95 | } |
96 | 96 | ||
97 | static inline int atomic_add_return(int i, atomic_t *v) | 97 | #define ATOMIC_OP(op) \ |
98 | { | 98 | static inline void atomic_##op(int i, atomic_t *v) \ |
99 | int output; | 99 | { \ |
100 | 100 | int output; \ | |
101 | __asm__ __volatile__ ( | 101 | \ |
102 | "1: %0 = memw_locked(%1);\n" | 102 | __asm__ __volatile__ ( \ |
103 | " %0 = add(%0,%2);\n" | 103 | "1: %0 = memw_locked(%1);\n" \ |
104 | " memw_locked(%1,P3)=%0;\n" | 104 | " %0 = "#op "(%0,%2);\n" \ |
105 | " if !P3 jump 1b;\n" | 105 | " memw_locked(%1,P3)=%0;\n" \ |
106 | : "=&r" (output) | 106 | " if !P3 jump 1b;\n" \ |
107 | : "r" (&v->counter), "r" (i) | 107 | : "=&r" (output) \ |
108 | : "memory", "p3" | 108 | : "r" (&v->counter), "r" (i) \ |
109 | ); | 109 | : "memory", "p3" \ |
110 | return output; | 110 | ); \ |
111 | 111 | } \ | |
112 | |||
113 | #define ATOMIC_OP_RETURN(op) \ | ||
114 | static inline int atomic_##op##_return(int i, atomic_t *v) \ | ||
115 | { \ | ||
116 | int output; \ | ||
117 | \ | ||
118 | __asm__ __volatile__ ( \ | ||
119 | "1: %0 = memw_locked(%1);\n" \ | ||
120 | " %0 = "#op "(%0,%2);\n" \ | ||
121 | " memw_locked(%1,P3)=%0;\n" \ | ||
122 | " if !P3 jump 1b;\n" \ | ||
123 | : "=&r" (output) \ | ||
124 | : "r" (&v->counter), "r" (i) \ | ||
125 | : "memory", "p3" \ | ||
126 | ); \ | ||
127 | return output; \ | ||
112 | } | 128 | } |
113 | 129 | ||
114 | #define atomic_add(i, v) atomic_add_return(i, (v)) | 130 | #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) |
115 | 131 | ||
116 | static inline int atomic_sub_return(int i, atomic_t *v) | 132 | ATOMIC_OPS(add) |
117 | { | 133 | ATOMIC_OPS(sub) |
118 | int output; | ||
119 | __asm__ __volatile__ ( | ||
120 | "1: %0 = memw_locked(%1);\n" | ||
121 | " %0 = sub(%0,%2);\n" | ||
122 | " memw_locked(%1,P3)=%0\n" | ||
123 | " if !P3 jump 1b;\n" | ||
124 | : "=&r" (output) | ||
125 | : "r" (&v->counter), "r" (i) | ||
126 | : "memory", "p3" | ||
127 | ); | ||
128 | return output; | ||
129 | } | ||
130 | 134 | ||
131 | #define atomic_sub(i, v) atomic_sub_return(i, (v)) | 135 | #undef ATOMIC_OPS |
136 | #undef ATOMIC_OP_RETURN | ||
137 | #undef ATOMIC_OP | ||
132 | 138 | ||
133 | /** | 139 | /** |
134 | * __atomic_add_unless - add unless the number is a given value | 140 | * __atomic_add_unless - add unless the number is a given value |
diff --git a/arch/ia64/include/asm/atomic.h b/arch/ia64/include/asm/atomic.h index 0f8bf48dadf3..0bf03501fe5c 100644 --- a/arch/ia64/include/asm/atomic.h +++ b/arch/ia64/include/asm/atomic.h | |||
@@ -21,68 +21,100 @@ | |||
21 | #define ATOMIC_INIT(i) { (i) } | 21 | #define ATOMIC_INIT(i) { (i) } |
22 | #define ATOMIC64_INIT(i) { (i) } | 22 | #define ATOMIC64_INIT(i) { (i) } |
23 | 23 | ||
24 | #define atomic_read(v) (*(volatile int *)&(v)->counter) | 24 | #define atomic_read(v) ACCESS_ONCE((v)->counter) |
25 | #define atomic64_read(v) (*(volatile long *)&(v)->counter) | 25 | #define atomic64_read(v) ACCESS_ONCE((v)->counter) |
26 | 26 | ||
27 | #define atomic_set(v,i) (((v)->counter) = (i)) | 27 | #define atomic_set(v,i) (((v)->counter) = (i)) |
28 | #define atomic64_set(v,i) (((v)->counter) = (i)) | 28 | #define atomic64_set(v,i) (((v)->counter) = (i)) |
29 | 29 | ||
30 | static __inline__ int | 30 | #define ATOMIC_OP(op, c_op) \ |
31 | ia64_atomic_add (int i, atomic_t *v) | 31 | static __inline__ int \ |
32 | { | 32 | ia64_atomic_##op (int i, atomic_t *v) \ |
33 | __s32 old, new; | 33 | { \ |
34 | CMPXCHG_BUGCHECK_DECL | 34 | __s32 old, new; \ |
35 | 35 | CMPXCHG_BUGCHECK_DECL \ | |
36 | do { | 36 | \ |
37 | CMPXCHG_BUGCHECK(v); | 37 | do { \ |
38 | old = atomic_read(v); | 38 | CMPXCHG_BUGCHECK(v); \ |
39 | new = old + i; | 39 | old = atomic_read(v); \ |
40 | } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic_t)) != old); | 40 | new = old c_op i; \ |
41 | return new; | 41 | } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic_t)) != old); \ |
42 | return new; \ | ||
42 | } | 43 | } |
43 | 44 | ||
44 | static __inline__ long | 45 | ATOMIC_OP(add, +) |
45 | ia64_atomic64_add (__s64 i, atomic64_t *v) | 46 | ATOMIC_OP(sub, -) |
46 | { | ||
47 | __s64 old, new; | ||
48 | CMPXCHG_BUGCHECK_DECL | ||
49 | |||
50 | do { | ||
51 | CMPXCHG_BUGCHECK(v); | ||
52 | old = atomic64_read(v); | ||
53 | new = old + i; | ||
54 | } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic64_t)) != old); | ||
55 | return new; | ||
56 | } | ||
57 | 47 | ||
58 | static __inline__ int | 48 | #undef ATOMIC_OP |
59 | ia64_atomic_sub (int i, atomic_t *v) | ||
60 | { | ||
61 | __s32 old, new; | ||
62 | CMPXCHG_BUGCHECK_DECL | ||
63 | |||
64 | do { | ||
65 | CMPXCHG_BUGCHECK(v); | ||
66 | old = atomic_read(v); | ||
67 | new = old - i; | ||
68 | } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic_t)) != old); | ||
69 | return new; | ||
70 | } | ||
71 | 49 | ||
72 | static __inline__ long | 50 | #define atomic_add_return(i,v) \ |
73 | ia64_atomic64_sub (__s64 i, atomic64_t *v) | 51 | ({ \ |
74 | { | 52 | int __ia64_aar_i = (i); \ |
75 | __s64 old, new; | 53 | (__builtin_constant_p(i) \ |
76 | CMPXCHG_BUGCHECK_DECL | 54 | && ( (__ia64_aar_i == 1) || (__ia64_aar_i == 4) \ |
77 | 55 | || (__ia64_aar_i == 8) || (__ia64_aar_i == 16) \ | |
78 | do { | 56 | || (__ia64_aar_i == -1) || (__ia64_aar_i == -4) \ |
79 | CMPXCHG_BUGCHECK(v); | 57 | || (__ia64_aar_i == -8) || (__ia64_aar_i == -16))) \ |
80 | old = atomic64_read(v); | 58 | ? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter) \ |
81 | new = old - i; | 59 | : ia64_atomic_add(__ia64_aar_i, v); \ |
82 | } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic64_t)) != old); | 60 | }) |
83 | return new; | 61 | |
62 | #define atomic_sub_return(i,v) \ | ||
63 | ({ \ | ||
64 | int __ia64_asr_i = (i); \ | ||
65 | (__builtin_constant_p(i) \ | ||
66 | && ( (__ia64_asr_i == 1) || (__ia64_asr_i == 4) \ | ||
67 | || (__ia64_asr_i == 8) || (__ia64_asr_i == 16) \ | ||
68 | || (__ia64_asr_i == -1) || (__ia64_asr_i == -4) \ | ||
69 | || (__ia64_asr_i == -8) || (__ia64_asr_i == -16))) \ | ||
70 | ? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter) \ | ||
71 | : ia64_atomic_sub(__ia64_asr_i, v); \ | ||
72 | }) | ||
73 | |||
74 | #define ATOMIC64_OP(op, c_op) \ | ||
75 | static __inline__ long \ | ||
76 | ia64_atomic64_##op (__s64 i, atomic64_t *v) \ | ||
77 | { \ | ||
78 | __s64 old, new; \ | ||
79 | CMPXCHG_BUGCHECK_DECL \ | ||
80 | \ | ||
81 | do { \ | ||
82 | CMPXCHG_BUGCHECK(v); \ | ||
83 | old = atomic64_read(v); \ | ||
84 | new = old c_op i; \ | ||
85 | } while (ia64_cmpxchg(acq, v, old, new, sizeof(atomic64_t)) != old); \ | ||
86 | return new; \ | ||
84 | } | 87 | } |
85 | 88 | ||
89 | ATOMIC64_OP(add, +) | ||
90 | ATOMIC64_OP(sub, -) | ||
91 | |||
92 | #undef ATOMIC64_OP | ||
93 | |||
94 | #define atomic64_add_return(i,v) \ | ||
95 | ({ \ | ||
96 | long __ia64_aar_i = (i); \ | ||
97 | (__builtin_constant_p(i) \ | ||
98 | && ( (__ia64_aar_i == 1) || (__ia64_aar_i == 4) \ | ||
99 | || (__ia64_aar_i == 8) || (__ia64_aar_i == 16) \ | ||
100 | || (__ia64_aar_i == -1) || (__ia64_aar_i == -4) \ | ||
101 | || (__ia64_aar_i == -8) || (__ia64_aar_i == -16))) \ | ||
102 | ? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter) \ | ||
103 | : ia64_atomic64_add(__ia64_aar_i, v); \ | ||
104 | }) | ||
105 | |||
106 | #define atomic64_sub_return(i,v) \ | ||
107 | ({ \ | ||
108 | long __ia64_asr_i = (i); \ | ||
109 | (__builtin_constant_p(i) \ | ||
110 | && ( (__ia64_asr_i == 1) || (__ia64_asr_i == 4) \ | ||
111 | || (__ia64_asr_i == 8) || (__ia64_asr_i == 16) \ | ||
112 | || (__ia64_asr_i == -1) || (__ia64_asr_i == -4) \ | ||
113 | || (__ia64_asr_i == -8) || (__ia64_asr_i == -16))) \ | ||
114 | ? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter) \ | ||
115 | : ia64_atomic64_sub(__ia64_asr_i, v); \ | ||
116 | }) | ||
117 | |||
86 | #define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new)) | 118 | #define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new)) |
87 | #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) | 119 | #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) |
88 | 120 | ||
@@ -123,30 +155,6 @@ static __inline__ long atomic64_add_unless(atomic64_t *v, long a, long u) | |||
123 | 155 | ||
124 | #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) | 156 | #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) |
125 | 157 | ||
126 | #define atomic_add_return(i,v) \ | ||
127 | ({ \ | ||
128 | int __ia64_aar_i = (i); \ | ||
129 | (__builtin_constant_p(i) \ | ||
130 | && ( (__ia64_aar_i == 1) || (__ia64_aar_i == 4) \ | ||
131 | || (__ia64_aar_i == 8) || (__ia64_aar_i == 16) \ | ||
132 | || (__ia64_aar_i == -1) || (__ia64_aar_i == -4) \ | ||
133 | || (__ia64_aar_i == -8) || (__ia64_aar_i == -16))) \ | ||
134 | ? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter) \ | ||
135 | : ia64_atomic_add(__ia64_aar_i, v); \ | ||
136 | }) | ||
137 | |||
138 | #define atomic64_add_return(i,v) \ | ||
139 | ({ \ | ||
140 | long __ia64_aar_i = (i); \ | ||
141 | (__builtin_constant_p(i) \ | ||
142 | && ( (__ia64_aar_i == 1) || (__ia64_aar_i == 4) \ | ||
143 | || (__ia64_aar_i == 8) || (__ia64_aar_i == 16) \ | ||
144 | || (__ia64_aar_i == -1) || (__ia64_aar_i == -4) \ | ||
145 | || (__ia64_aar_i == -8) || (__ia64_aar_i == -16))) \ | ||
146 | ? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter) \ | ||
147 | : ia64_atomic64_add(__ia64_aar_i, v); \ | ||
148 | }) | ||
149 | |||
150 | /* | 158 | /* |
151 | * Atomically add I to V and return TRUE if the resulting value is | 159 | * Atomically add I to V and return TRUE if the resulting value is |
152 | * negative. | 160 | * negative. |
@@ -163,30 +171,6 @@ atomic64_add_negative (__s64 i, atomic64_t *v) | |||
163 | return atomic64_add_return(i, v) < 0; | 171 | return atomic64_add_return(i, v) < 0; |
164 | } | 172 | } |
165 | 173 | ||
166 | #define atomic_sub_return(i,v) \ | ||
167 | ({ \ | ||
168 | int __ia64_asr_i = (i); \ | ||
169 | (__builtin_constant_p(i) \ | ||
170 | && ( (__ia64_asr_i == 1) || (__ia64_asr_i == 4) \ | ||
171 | || (__ia64_asr_i == 8) || (__ia64_asr_i == 16) \ | ||
172 | || (__ia64_asr_i == -1) || (__ia64_asr_i == -4) \ | ||
173 | || (__ia64_asr_i == -8) || (__ia64_asr_i == -16))) \ | ||
174 | ? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter) \ | ||
175 | : ia64_atomic_sub(__ia64_asr_i, v); \ | ||
176 | }) | ||
177 | |||
178 | #define atomic64_sub_return(i,v) \ | ||
179 | ({ \ | ||
180 | long __ia64_asr_i = (i); \ | ||
181 | (__builtin_constant_p(i) \ | ||
182 | && ( (__ia64_asr_i == 1) || (__ia64_asr_i == 4) \ | ||
183 | || (__ia64_asr_i == 8) || (__ia64_asr_i == 16) \ | ||
184 | || (__ia64_asr_i == -1) || (__ia64_asr_i == -4) \ | ||
185 | || (__ia64_asr_i == -8) || (__ia64_asr_i == -16))) \ | ||
186 | ? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter) \ | ||
187 | : ia64_atomic64_sub(__ia64_asr_i, v); \ | ||
188 | }) | ||
189 | |||
190 | #define atomic_dec_return(v) atomic_sub_return(1, (v)) | 174 | #define atomic_dec_return(v) atomic_sub_return(1, (v)) |
191 | #define atomic_inc_return(v) atomic_add_return(1, (v)) | 175 | #define atomic_inc_return(v) atomic_add_return(1, (v)) |
192 | #define atomic64_dec_return(v) atomic64_sub_return(1, (v)) | 176 | #define atomic64_dec_return(v) atomic64_sub_return(1, (v)) |
@@ -199,13 +183,13 @@ atomic64_add_negative (__s64 i, atomic64_t *v) | |||
199 | #define atomic64_dec_and_test(v) (atomic64_sub_return(1, (v)) == 0) | 183 | #define atomic64_dec_and_test(v) (atomic64_sub_return(1, (v)) == 0) |
200 | #define atomic64_inc_and_test(v) (atomic64_add_return(1, (v)) == 0) | 184 | #define atomic64_inc_and_test(v) (atomic64_add_return(1, (v)) == 0) |
201 | 185 | ||
202 | #define atomic_add(i,v) atomic_add_return((i), (v)) | 186 | #define atomic_add(i,v) (void)atomic_add_return((i), (v)) |
203 | #define atomic_sub(i,v) atomic_sub_return((i), (v)) | 187 | #define atomic_sub(i,v) (void)atomic_sub_return((i), (v)) |
204 | #define atomic_inc(v) atomic_add(1, (v)) | 188 | #define atomic_inc(v) atomic_add(1, (v)) |
205 | #define atomic_dec(v) atomic_sub(1, (v)) | 189 | #define atomic_dec(v) atomic_sub(1, (v)) |
206 | 190 | ||
207 | #define atomic64_add(i,v) atomic64_add_return((i), (v)) | 191 | #define atomic64_add(i,v) (void)atomic64_add_return((i), (v)) |
208 | #define atomic64_sub(i,v) atomic64_sub_return((i), (v)) | 192 | #define atomic64_sub(i,v) (void)atomic64_sub_return((i), (v)) |
209 | #define atomic64_inc(v) atomic64_add(1, (v)) | 193 | #define atomic64_inc(v) atomic64_add(1, (v)) |
210 | #define atomic64_dec(v) atomic64_sub(1, (v)) | 194 | #define atomic64_dec(v) atomic64_sub(1, (v)) |
211 | 195 | ||
diff --git a/arch/m32r/include/asm/atomic.h b/arch/m32r/include/asm/atomic.h index 8ad0ed4182a5..31bb74adba08 100644 --- a/arch/m32r/include/asm/atomic.h +++ b/arch/m32r/include/asm/atomic.h | |||
@@ -28,7 +28,7 @@ | |||
28 | * | 28 | * |
29 | * Atomically reads the value of @v. | 29 | * Atomically reads the value of @v. |
30 | */ | 30 | */ |
31 | #define atomic_read(v) (*(volatile int *)&(v)->counter) | 31 | #define atomic_read(v) ACCESS_ONCE((v)->counter) |
32 | 32 | ||
33 | /** | 33 | /** |
34 | * atomic_set - set atomic variable | 34 | * atomic_set - set atomic variable |
@@ -39,85 +39,64 @@ | |||
39 | */ | 39 | */ |
40 | #define atomic_set(v,i) (((v)->counter) = (i)) | 40 | #define atomic_set(v,i) (((v)->counter) = (i)) |
41 | 41 | ||
42 | /** | ||
43 | * atomic_add_return - add integer to atomic variable and return it | ||
44 | * @i: integer value to add | ||
45 | * @v: pointer of type atomic_t | ||
46 | * | ||
47 | * Atomically adds @i to @v and return (@i + @v). | ||
48 | */ | ||
49 | static __inline__ int atomic_add_return(int i, atomic_t *v) | ||
50 | { | ||
51 | unsigned long flags; | ||
52 | int result; | ||
53 | |||
54 | local_irq_save(flags); | ||
55 | __asm__ __volatile__ ( | ||
56 | "# atomic_add_return \n\t" | ||
57 | DCACHE_CLEAR("%0", "r4", "%1") | ||
58 | M32R_LOCK" %0, @%1; \n\t" | ||
59 | "add %0, %2; \n\t" | ||
60 | M32R_UNLOCK" %0, @%1; \n\t" | ||
61 | : "=&r" (result) | ||
62 | : "r" (&v->counter), "r" (i) | ||
63 | : "memory" | ||
64 | #ifdef CONFIG_CHIP_M32700_TS1 | 42 | #ifdef CONFIG_CHIP_M32700_TS1 |
65 | , "r4" | 43 | #define __ATOMIC_CLOBBER , "r4" |
66 | #endif /* CONFIG_CHIP_M32700_TS1 */ | 44 | #else |
67 | ); | 45 | #define __ATOMIC_CLOBBER |
68 | local_irq_restore(flags); | 46 | #endif |
69 | 47 | ||
70 | return result; | 48 | #define ATOMIC_OP(op) \ |
49 | static __inline__ void atomic_##op(int i, atomic_t *v) \ | ||
50 | { \ | ||
51 | unsigned long flags; \ | ||
52 | int result; \ | ||
53 | \ | ||
54 | local_irq_save(flags); \ | ||
55 | __asm__ __volatile__ ( \ | ||
56 | "# atomic_" #op " \n\t" \ | ||
57 | DCACHE_CLEAR("%0", "r4", "%1") \ | ||
58 | M32R_LOCK" %0, @%1; \n\t" \ | ||
59 | #op " %0, %2; \n\t" \ | ||
60 | M32R_UNLOCK" %0, @%1; \n\t" \ | ||
61 | : "=&r" (result) \ | ||
62 | : "r" (&v->counter), "r" (i) \ | ||
63 | : "memory" \ | ||
64 | __ATOMIC_CLOBBER \ | ||
65 | ); \ | ||
66 | local_irq_restore(flags); \ | ||
67 | } \ | ||
68 | |||
69 | #define ATOMIC_OP_RETURN(op) \ | ||
70 | static __inline__ int atomic_##op##_return(int i, atomic_t *v) \ | ||
71 | { \ | ||
72 | unsigned long flags; \ | ||
73 | int result; \ | ||
74 | \ | ||
75 | local_irq_save(flags); \ | ||
76 | __asm__ __volatile__ ( \ | ||
77 | "# atomic_" #op "_return \n\t" \ | ||
78 | DCACHE_CLEAR("%0", "r4", "%1") \ | ||
79 | M32R_LOCK" %0, @%1; \n\t" \ | ||
80 | #op " %0, %2; \n\t" \ | ||
81 | M32R_UNLOCK" %0, @%1; \n\t" \ | ||
82 | : "=&r" (result) \ | ||
83 | : "r" (&v->counter), "r" (i) \ | ||
84 | : "memory" \ | ||
85 | __ATOMIC_CLOBBER \ | ||
86 | ); \ | ||
87 | local_irq_restore(flags); \ | ||
88 | \ | ||
89 | return result; \ | ||
71 | } | 90 | } |
72 | 91 | ||
73 | /** | 92 | #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) |
74 | * atomic_sub_return - subtract integer from atomic variable and return it | ||
75 | * @i: integer value to subtract | ||
76 | * @v: pointer of type atomic_t | ||
77 | * | ||
78 | * Atomically subtracts @i from @v and return (@v - @i). | ||
79 | */ | ||
80 | static __inline__ int atomic_sub_return(int i, atomic_t *v) | ||
81 | { | ||
82 | unsigned long flags; | ||
83 | int result; | ||
84 | |||
85 | local_irq_save(flags); | ||
86 | __asm__ __volatile__ ( | ||
87 | "# atomic_sub_return \n\t" | ||
88 | DCACHE_CLEAR("%0", "r4", "%1") | ||
89 | M32R_LOCK" %0, @%1; \n\t" | ||
90 | "sub %0, %2; \n\t" | ||
91 | M32R_UNLOCK" %0, @%1; \n\t" | ||
92 | : "=&r" (result) | ||
93 | : "r" (&v->counter), "r" (i) | ||
94 | : "memory" | ||
95 | #ifdef CONFIG_CHIP_M32700_TS1 | ||
96 | , "r4" | ||
97 | #endif /* CONFIG_CHIP_M32700_TS1 */ | ||
98 | ); | ||
99 | local_irq_restore(flags); | ||
100 | |||
101 | return result; | ||
102 | } | ||
103 | 93 | ||
104 | /** | 94 | ATOMIC_OPS(add) |
105 | * atomic_add - add integer to atomic variable | 95 | ATOMIC_OPS(sub) |
106 | * @i: integer value to add | ||
107 | * @v: pointer of type atomic_t | ||
108 | * | ||
109 | * Atomically adds @i to @v. | ||
110 | */ | ||
111 | #define atomic_add(i,v) ((void) atomic_add_return((i), (v))) | ||
112 | 96 | ||
113 | /** | 97 | #undef ATOMIC_OPS |
114 | * atomic_sub - subtract the atomic variable | 98 | #undef ATOMIC_OP_RETURN |
115 | * @i: integer value to subtract | 99 | #undef ATOMIC_OP |
116 | * @v: pointer of type atomic_t | ||
117 | * | ||
118 | * Atomically subtracts @i from @v. | ||
119 | */ | ||
120 | #define atomic_sub(i,v) ((void) atomic_sub_return((i), (v))) | ||
121 | 100 | ||
122 | /** | 101 | /** |
123 | * atomic_sub_and_test - subtract value from variable and test result | 102 | * atomic_sub_and_test - subtract value from variable and test result |
@@ -151,9 +130,7 @@ static __inline__ int atomic_inc_return(atomic_t *v) | |||
151 | : "=&r" (result) | 130 | : "=&r" (result) |
152 | : "r" (&v->counter) | 131 | : "r" (&v->counter) |
153 | : "memory" | 132 | : "memory" |
154 | #ifdef CONFIG_CHIP_M32700_TS1 | 133 | __ATOMIC_CLOBBER |
155 | , "r4" | ||
156 | #endif /* CONFIG_CHIP_M32700_TS1 */ | ||
157 | ); | 134 | ); |
158 | local_irq_restore(flags); | 135 | local_irq_restore(flags); |
159 | 136 | ||
@@ -181,9 +158,7 @@ static __inline__ int atomic_dec_return(atomic_t *v) | |||
181 | : "=&r" (result) | 158 | : "=&r" (result) |
182 | : "r" (&v->counter) | 159 | : "r" (&v->counter) |
183 | : "memory" | 160 | : "memory" |
184 | #ifdef CONFIG_CHIP_M32700_TS1 | 161 | __ATOMIC_CLOBBER |
185 | , "r4" | ||
186 | #endif /* CONFIG_CHIP_M32700_TS1 */ | ||
187 | ); | 162 | ); |
188 | local_irq_restore(flags); | 163 | local_irq_restore(flags); |
189 | 164 | ||
@@ -280,9 +255,7 @@ static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *addr) | |||
280 | : "=&r" (tmp) | 255 | : "=&r" (tmp) |
281 | : "r" (addr), "r" (~mask) | 256 | : "r" (addr), "r" (~mask) |
282 | : "memory" | 257 | : "memory" |
283 | #ifdef CONFIG_CHIP_M32700_TS1 | 258 | __ATOMIC_CLOBBER |
284 | , "r5" | ||
285 | #endif /* CONFIG_CHIP_M32700_TS1 */ | ||
286 | ); | 259 | ); |
287 | local_irq_restore(flags); | 260 | local_irq_restore(flags); |
288 | } | 261 | } |
@@ -302,9 +275,7 @@ static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *addr) | |||
302 | : "=&r" (tmp) | 275 | : "=&r" (tmp) |
303 | : "r" (addr), "r" (mask) | 276 | : "r" (addr), "r" (mask) |
304 | : "memory" | 277 | : "memory" |
305 | #ifdef CONFIG_CHIP_M32700_TS1 | 278 | __ATOMIC_CLOBBER |
306 | , "r5" | ||
307 | #endif /* CONFIG_CHIP_M32700_TS1 */ | ||
308 | ); | 279 | ); |
309 | local_irq_restore(flags); | 280 | local_irq_restore(flags); |
310 | } | 281 | } |
diff --git a/arch/m68k/include/asm/atomic.h b/arch/m68k/include/asm/atomic.h index 55695212a2ae..e85f047fb072 100644 --- a/arch/m68k/include/asm/atomic.h +++ b/arch/m68k/include/asm/atomic.h | |||
@@ -17,7 +17,7 @@ | |||
17 | 17 | ||
18 | #define ATOMIC_INIT(i) { (i) } | 18 | #define ATOMIC_INIT(i) { (i) } |
19 | 19 | ||
20 | #define atomic_read(v) (*(volatile int *)&(v)->counter) | 20 | #define atomic_read(v) ACCESS_ONCE((v)->counter) |
21 | #define atomic_set(v, i) (((v)->counter) = i) | 21 | #define atomic_set(v, i) (((v)->counter) = i) |
22 | 22 | ||
23 | /* | 23 | /* |
@@ -30,16 +30,57 @@ | |||
30 | #define ASM_DI "di" | 30 | #define ASM_DI "di" |
31 | #endif | 31 | #endif |
32 | 32 | ||
33 | static inline void atomic_add(int i, atomic_t *v) | 33 | #define ATOMIC_OP(op, c_op, asm_op) \ |
34 | { | 34 | static inline void atomic_##op(int i, atomic_t *v) \ |
35 | __asm__ __volatile__("addl %1,%0" : "+m" (*v) : ASM_DI (i)); | 35 | { \ |
36 | __asm__ __volatile__(#asm_op "l %1,%0" : "+m" (*v) : ASM_DI (i));\ | ||
37 | } \ | ||
38 | |||
39 | #ifdef CONFIG_RMW_INSNS | ||
40 | |||
41 | #define ATOMIC_OP_RETURN(op, c_op, asm_op) \ | ||
42 | static inline int atomic_##op##_return(int i, atomic_t *v) \ | ||
43 | { \ | ||
44 | int t, tmp; \ | ||
45 | \ | ||
46 | __asm__ __volatile__( \ | ||
47 | "1: movel %2,%1\n" \ | ||
48 | " " #asm_op "l %3,%1\n" \ | ||
49 | " casl %2,%1,%0\n" \ | ||
50 | " jne 1b" \ | ||
51 | : "+m" (*v), "=&d" (t), "=&d" (tmp) \ | ||
52 | : "g" (i), "2" (atomic_read(v))); \ | ||
53 | return t; \ | ||
36 | } | 54 | } |
37 | 55 | ||
38 | static inline void atomic_sub(int i, atomic_t *v) | 56 | #else |
39 | { | 57 | |
40 | __asm__ __volatile__("subl %1,%0" : "+m" (*v) : ASM_DI (i)); | 58 | #define ATOMIC_OP_RETURN(op, c_op, asm_op) \ |
59 | static inline int atomic_##op##_return(int i, atomic_t * v) \ | ||
60 | { \ | ||
61 | unsigned long flags; \ | ||
62 | int t; \ | ||
63 | \ | ||
64 | local_irq_save(flags); \ | ||
65 | t = (v->counter c_op i); \ | ||
66 | local_irq_restore(flags); \ | ||
67 | \ | ||
68 | return t; \ | ||
41 | } | 69 | } |
42 | 70 | ||
71 | #endif /* CONFIG_RMW_INSNS */ | ||
72 | |||
73 | #define ATOMIC_OPS(op, c_op, asm_op) \ | ||
74 | ATOMIC_OP(op, c_op, asm_op) \ | ||
75 | ATOMIC_OP_RETURN(op, c_op, asm_op) | ||
76 | |||
77 | ATOMIC_OPS(add, +=, add) | ||
78 | ATOMIC_OPS(sub, -=, sub) | ||
79 | |||
80 | #undef ATOMIC_OPS | ||
81 | #undef ATOMIC_OP_RETURN | ||
82 | #undef ATOMIC_OP | ||
83 | |||
43 | static inline void atomic_inc(atomic_t *v) | 84 | static inline void atomic_inc(atomic_t *v) |
44 | { | 85 | { |
45 | __asm__ __volatile__("addql #1,%0" : "+m" (*v)); | 86 | __asm__ __volatile__("addql #1,%0" : "+m" (*v)); |
@@ -76,67 +117,11 @@ static inline int atomic_inc_and_test(atomic_t *v) | |||
76 | 117 | ||
77 | #ifdef CONFIG_RMW_INSNS | 118 | #ifdef CONFIG_RMW_INSNS |
78 | 119 | ||
79 | static inline int atomic_add_return(int i, atomic_t *v) | ||
80 | { | ||
81 | int t, tmp; | ||
82 | |||
83 | __asm__ __volatile__( | ||
84 | "1: movel %2,%1\n" | ||
85 | " addl %3,%1\n" | ||
86 | " casl %2,%1,%0\n" | ||
87 | " jne 1b" | ||
88 | : "+m" (*v), "=&d" (t), "=&d" (tmp) | ||
89 | : "g" (i), "2" (atomic_read(v))); | ||
90 | return t; | ||
91 | } | ||
92 | |||
93 | static inline int atomic_sub_return(int i, atomic_t *v) | ||
94 | { | ||
95 | int t, tmp; | ||
96 | |||
97 | __asm__ __volatile__( | ||
98 | "1: movel %2,%1\n" | ||
99 | " subl %3,%1\n" | ||
100 | " casl %2,%1,%0\n" | ||
101 | " jne 1b" | ||
102 | : "+m" (*v), "=&d" (t), "=&d" (tmp) | ||
103 | : "g" (i), "2" (atomic_read(v))); | ||
104 | return t; | ||
105 | } | ||
106 | |||
107 | #define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n))) | 120 | #define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n))) |
108 | #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) | 121 | #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) |
109 | 122 | ||
110 | #else /* !CONFIG_RMW_INSNS */ | 123 | #else /* !CONFIG_RMW_INSNS */ |
111 | 124 | ||
112 | static inline int atomic_add_return(int i, atomic_t * v) | ||
113 | { | ||
114 | unsigned long flags; | ||
115 | int t; | ||
116 | |||
117 | local_irq_save(flags); | ||
118 | t = atomic_read(v); | ||
119 | t += i; | ||
120 | atomic_set(v, t); | ||
121 | local_irq_restore(flags); | ||
122 | |||
123 | return t; | ||
124 | } | ||
125 | |||
126 | static inline int atomic_sub_return(int i, atomic_t * v) | ||
127 | { | ||
128 | unsigned long flags; | ||
129 | int t; | ||
130 | |||
131 | local_irq_save(flags); | ||
132 | t = atomic_read(v); | ||
133 | t -= i; | ||
134 | atomic_set(v, t); | ||
135 | local_irq_restore(flags); | ||
136 | |||
137 | return t; | ||
138 | } | ||
139 | |||
140 | static inline int atomic_cmpxchg(atomic_t *v, int old, int new) | 125 | static inline int atomic_cmpxchg(atomic_t *v, int old, int new) |
141 | { | 126 | { |
142 | unsigned long flags; | 127 | unsigned long flags; |
diff --git a/arch/metag/include/asm/atomic_lnkget.h b/arch/metag/include/asm/atomic_lnkget.h index d2e60a18986c..948d8688643c 100644 --- a/arch/metag/include/asm/atomic_lnkget.h +++ b/arch/metag/include/asm/atomic_lnkget.h | |||
@@ -27,85 +27,56 @@ static inline int atomic_read(const atomic_t *v) | |||
27 | return temp; | 27 | return temp; |
28 | } | 28 | } |
29 | 29 | ||
30 | static inline void atomic_add(int i, atomic_t *v) | 30 | #define ATOMIC_OP(op) \ |
31 | { | 31 | static inline void atomic_##op(int i, atomic_t *v) \ |
32 | int temp; | 32 | { \ |
33 | 33 | int temp; \ | |
34 | asm volatile ( | 34 | \ |
35 | "1: LNKGETD %0, [%1]\n" | 35 | asm volatile ( \ |
36 | " ADD %0, %0, %2\n" | 36 | "1: LNKGETD %0, [%1]\n" \ |
37 | " LNKSETD [%1], %0\n" | 37 | " " #op " %0, %0, %2\n" \ |
38 | " DEFR %0, TXSTAT\n" | 38 | " LNKSETD [%1], %0\n" \ |
39 | " ANDT %0, %0, #HI(0x3f000000)\n" | 39 | " DEFR %0, TXSTAT\n" \ |
40 | " CMPT %0, #HI(0x02000000)\n" | 40 | " ANDT %0, %0, #HI(0x3f000000)\n" \ |
41 | " BNZ 1b\n" | 41 | " CMPT %0, #HI(0x02000000)\n" \ |
42 | : "=&d" (temp) | 42 | " BNZ 1b\n" \ |
43 | : "da" (&v->counter), "bd" (i) | 43 | : "=&d" (temp) \ |
44 | : "cc"); | 44 | : "da" (&v->counter), "bd" (i) \ |
45 | : "cc"); \ | ||
46 | } \ | ||
47 | |||
48 | #define ATOMIC_OP_RETURN(op) \ | ||
49 | static inline int atomic_##op##_return(int i, atomic_t *v) \ | ||
50 | { \ | ||
51 | int result, temp; \ | ||
52 | \ | ||
53 | smp_mb(); \ | ||
54 | \ | ||
55 | asm volatile ( \ | ||
56 | "1: LNKGETD %1, [%2]\n" \ | ||
57 | " " #op " %1, %1, %3\n" \ | ||
58 | " LNKSETD [%2], %1\n" \ | ||
59 | " DEFR %0, TXSTAT\n" \ | ||
60 | " ANDT %0, %0, #HI(0x3f000000)\n" \ | ||
61 | " CMPT %0, #HI(0x02000000)\n" \ | ||
62 | " BNZ 1b\n" \ | ||
63 | : "=&d" (temp), "=&da" (result) \ | ||
64 | : "da" (&v->counter), "bd" (i) \ | ||
65 | : "cc"); \ | ||
66 | \ | ||
67 | smp_mb(); \ | ||
68 | \ | ||
69 | return result; \ | ||
45 | } | 70 | } |
46 | 71 | ||
47 | static inline void atomic_sub(int i, atomic_t *v) | 72 | #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) |
48 | { | ||
49 | int temp; | ||
50 | 73 | ||
51 | asm volatile ( | 74 | ATOMIC_OPS(add) |
52 | "1: LNKGETD %0, [%1]\n" | 75 | ATOMIC_OPS(sub) |
53 | " SUB %0, %0, %2\n" | ||
54 | " LNKSETD [%1], %0\n" | ||
55 | " DEFR %0, TXSTAT\n" | ||
56 | " ANDT %0, %0, #HI(0x3f000000)\n" | ||
57 | " CMPT %0, #HI(0x02000000)\n" | ||
58 | " BNZ 1b\n" | ||
59 | : "=&d" (temp) | ||
60 | : "da" (&v->counter), "bd" (i) | ||
61 | : "cc"); | ||
62 | } | ||
63 | 76 | ||
64 | static inline int atomic_add_return(int i, atomic_t *v) | 77 | #undef ATOMIC_OPS |
65 | { | 78 | #undef ATOMIC_OP_RETURN |
66 | int result, temp; | 79 | #undef ATOMIC_OP |
67 | |||
68 | smp_mb(); | ||
69 | |||
70 | asm volatile ( | ||
71 | "1: LNKGETD %1, [%2]\n" | ||
72 | " ADD %1, %1, %3\n" | ||
73 | " LNKSETD [%2], %1\n" | ||
74 | " DEFR %0, TXSTAT\n" | ||
75 | " ANDT %0, %0, #HI(0x3f000000)\n" | ||
76 | " CMPT %0, #HI(0x02000000)\n" | ||
77 | " BNZ 1b\n" | ||
78 | : "=&d" (temp), "=&da" (result) | ||
79 | : "da" (&v->counter), "bd" (i) | ||
80 | : "cc"); | ||
81 | |||
82 | smp_mb(); | ||
83 | |||
84 | return result; | ||
85 | } | ||
86 | |||
87 | static inline int atomic_sub_return(int i, atomic_t *v) | ||
88 | { | ||
89 | int result, temp; | ||
90 | |||
91 | smp_mb(); | ||
92 | |||
93 | asm volatile ( | ||
94 | "1: LNKGETD %1, [%2]\n" | ||
95 | " SUB %1, %1, %3\n" | ||
96 | " LNKSETD [%2], %1\n" | ||
97 | " DEFR %0, TXSTAT\n" | ||
98 | " ANDT %0, %0, #HI(0x3f000000)\n" | ||
99 | " CMPT %0, #HI(0x02000000)\n" | ||
100 | " BNZ 1b\n" | ||
101 | : "=&d" (temp), "=&da" (result) | ||
102 | : "da" (&v->counter), "bd" (i) | ||
103 | : "cc"); | ||
104 | |||
105 | smp_mb(); | ||
106 | |||
107 | return result; | ||
108 | } | ||
109 | 80 | ||
110 | static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) | 81 | static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) |
111 | { | 82 | { |
diff --git a/arch/metag/include/asm/atomic_lock1.h b/arch/metag/include/asm/atomic_lock1.h index e578955e674b..f5d5898c1020 100644 --- a/arch/metag/include/asm/atomic_lock1.h +++ b/arch/metag/include/asm/atomic_lock1.h | |||
@@ -37,55 +37,41 @@ static inline int atomic_set(atomic_t *v, int i) | |||
37 | return i; | 37 | return i; |
38 | } | 38 | } |
39 | 39 | ||
40 | static inline void atomic_add(int i, atomic_t *v) | 40 | #define ATOMIC_OP(op, c_op) \ |
41 | { | 41 | static inline void atomic_##op(int i, atomic_t *v) \ |
42 | unsigned long flags; | 42 | { \ |
43 | 43 | unsigned long flags; \ | |
44 | __global_lock1(flags); | 44 | \ |
45 | fence(); | 45 | __global_lock1(flags); \ |
46 | v->counter += i; | 46 | fence(); \ |
47 | __global_unlock1(flags); | 47 | v->counter c_op i; \ |
48 | __global_unlock1(flags); \ | ||
49 | } \ | ||
50 | |||
51 | #define ATOMIC_OP_RETURN(op, c_op) \ | ||
52 | static inline int atomic_##op##_return(int i, atomic_t *v) \ | ||
53 | { \ | ||
54 | unsigned long result; \ | ||
55 | unsigned long flags; \ | ||
56 | \ | ||
57 | __global_lock1(flags); \ | ||
58 | result = v->counter; \ | ||
59 | result c_op i; \ | ||
60 | fence(); \ | ||
61 | v->counter = result; \ | ||
62 | __global_unlock1(flags); \ | ||
63 | \ | ||
64 | return result; \ | ||
48 | } | 65 | } |
49 | 66 | ||
50 | static inline void atomic_sub(int i, atomic_t *v) | 67 | #define ATOMIC_OPS(op, c_op) ATOMIC_OP(op, c_op) ATOMIC_OP_RETURN(op, c_op) |
51 | { | ||
52 | unsigned long flags; | ||
53 | 68 | ||
54 | __global_lock1(flags); | 69 | ATOMIC_OPS(add, +=) |
55 | fence(); | 70 | ATOMIC_OPS(sub, -=) |
56 | v->counter -= i; | ||
57 | __global_unlock1(flags); | ||
58 | } | ||
59 | |||
60 | static inline int atomic_add_return(int i, atomic_t *v) | ||
61 | { | ||
62 | unsigned long result; | ||
63 | unsigned long flags; | ||
64 | 71 | ||
65 | __global_lock1(flags); | 72 | #undef ATOMIC_OPS |
66 | result = v->counter; | 73 | #undef ATOMIC_OP_RETURN |
67 | result += i; | 74 | #undef ATOMIC_OP |
68 | fence(); | ||
69 | v->counter = result; | ||
70 | __global_unlock1(flags); | ||
71 | |||
72 | return result; | ||
73 | } | ||
74 | |||
75 | static inline int atomic_sub_return(int i, atomic_t *v) | ||
76 | { | ||
77 | unsigned long result; | ||
78 | unsigned long flags; | ||
79 | |||
80 | __global_lock1(flags); | ||
81 | result = v->counter; | ||
82 | result -= i; | ||
83 | fence(); | ||
84 | v->counter = result; | ||
85 | __global_unlock1(flags); | ||
86 | |||
87 | return result; | ||
88 | } | ||
89 | 75 | ||
90 | static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) | 76 | static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) |
91 | { | 77 | { |
diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h index 37b2befe651a..6dd6bfc607e9 100644 --- a/arch/mips/include/asm/atomic.h +++ b/arch/mips/include/asm/atomic.h | |||
@@ -29,7 +29,7 @@ | |||
29 | * | 29 | * |
30 | * Atomically reads the value of @v. | 30 | * Atomically reads the value of @v. |
31 | */ | 31 | */ |
32 | #define atomic_read(v) (*(volatile int *)&(v)->counter) | 32 | #define atomic_read(v) ACCESS_ONCE((v)->counter) |
33 | 33 | ||
34 | /* | 34 | /* |
35 | * atomic_set - set atomic variable | 35 | * atomic_set - set atomic variable |
@@ -40,195 +40,103 @@ | |||
40 | */ | 40 | */ |
41 | #define atomic_set(v, i) ((v)->counter = (i)) | 41 | #define atomic_set(v, i) ((v)->counter = (i)) |
42 | 42 | ||
43 | /* | 43 | #define ATOMIC_OP(op, c_op, asm_op) \ |
44 | * atomic_add - add integer to atomic variable | 44 | static __inline__ void atomic_##op(int i, atomic_t * v) \ |
45 | * @i: integer value to add | 45 | { \ |
46 | * @v: pointer of type atomic_t | 46 | if (kernel_uses_llsc && R10000_LLSC_WAR) { \ |
47 | * | 47 | int temp; \ |
48 | * Atomically adds @i to @v. | 48 | \ |
49 | */ | 49 | __asm__ __volatile__( \ |
50 | static __inline__ void atomic_add(int i, atomic_t * v) | 50 | " .set arch=r4000 \n" \ |
51 | { | 51 | "1: ll %0, %1 # atomic_" #op " \n" \ |
52 | if (kernel_uses_llsc && R10000_LLSC_WAR) { | 52 | " " #asm_op " %0, %2 \n" \ |
53 | int temp; | 53 | " sc %0, %1 \n" \ |
54 | 54 | " beqzl %0, 1b \n" \ | |
55 | __asm__ __volatile__( | 55 | " .set mips0 \n" \ |
56 | " .set arch=r4000 \n" | 56 | : "=&r" (temp), "+m" (v->counter) \ |
57 | "1: ll %0, %1 # atomic_add \n" | 57 | : "Ir" (i)); \ |
58 | " addu %0, %2 \n" | 58 | } else if (kernel_uses_llsc) { \ |
59 | " sc %0, %1 \n" | 59 | int temp; \ |
60 | " beqzl %0, 1b \n" | 60 | \ |
61 | " .set mips0 \n" | 61 | do { \ |
62 | : "=&r" (temp), "+m" (v->counter) | 62 | __asm__ __volatile__( \ |
63 | : "Ir" (i)); | 63 | " .set arch=r4000 \n" \ |
64 | } else if (kernel_uses_llsc) { | 64 | " ll %0, %1 # atomic_" #op "\n" \ |
65 | int temp; | 65 | " " #asm_op " %0, %2 \n" \ |
66 | 66 | " sc %0, %1 \n" \ | |
67 | do { | 67 | " .set mips0 \n" \ |
68 | __asm__ __volatile__( | 68 | : "=&r" (temp), "+m" (v->counter) \ |
69 | " .set arch=r4000 \n" | 69 | : "Ir" (i)); \ |
70 | " ll %0, %1 # atomic_add \n" | 70 | } while (unlikely(!temp)); \ |
71 | " addu %0, %2 \n" | 71 | } else { \ |
72 | " sc %0, %1 \n" | 72 | unsigned long flags; \ |
73 | " .set mips0 \n" | 73 | \ |
74 | : "=&r" (temp), "+m" (v->counter) | 74 | raw_local_irq_save(flags); \ |
75 | : "Ir" (i)); | 75 | v->counter c_op i; \ |
76 | } while (unlikely(!temp)); | 76 | raw_local_irq_restore(flags); \ |
77 | } else { | 77 | } \ |
78 | unsigned long flags; | 78 | } \ |
79 | 79 | ||
80 | raw_local_irq_save(flags); | 80 | #define ATOMIC_OP_RETURN(op, c_op, asm_op) \ |
81 | v->counter += i; | 81 | static __inline__ int atomic_##op##_return(int i, atomic_t * v) \ |
82 | raw_local_irq_restore(flags); | 82 | { \ |
83 | } | 83 | int result; \ |
84 | } | 84 | \ |
85 | 85 | smp_mb__before_llsc(); \ | |
86 | /* | 86 | \ |
87 | * atomic_sub - subtract the atomic variable | 87 | if (kernel_uses_llsc && R10000_LLSC_WAR) { \ |
88 | * @i: integer value to subtract | 88 | int temp; \ |
89 | * @v: pointer of type atomic_t | 89 | \ |
90 | * | 90 | __asm__ __volatile__( \ |
91 | * Atomically subtracts @i from @v. | 91 | " .set arch=r4000 \n" \ |
92 | */ | 92 | "1: ll %1, %2 # atomic_" #op "_return \n" \ |
93 | static __inline__ void atomic_sub(int i, atomic_t * v) | 93 | " " #asm_op " %0, %1, %3 \n" \ |
94 | { | 94 | " sc %0, %2 \n" \ |
95 | if (kernel_uses_llsc && R10000_LLSC_WAR) { | 95 | " beqzl %0, 1b \n" \ |
96 | int temp; | 96 | " " #asm_op " %0, %1, %3 \n" \ |
97 | 97 | " .set mips0 \n" \ | |
98 | __asm__ __volatile__( | 98 | : "=&r" (result), "=&r" (temp), "+m" (v->counter) \ |
99 | " .set arch=r4000 \n" | 99 | : "Ir" (i)); \ |
100 | "1: ll %0, %1 # atomic_sub \n" | 100 | } else if (kernel_uses_llsc) { \ |
101 | " subu %0, %2 \n" | 101 | int temp; \ |
102 | " sc %0, %1 \n" | 102 | \ |
103 | " beqzl %0, 1b \n" | 103 | do { \ |
104 | " .set mips0 \n" | 104 | __asm__ __volatile__( \ |
105 | : "=&r" (temp), "+m" (v->counter) | 105 | " .set arch=r4000 \n" \ |
106 | : "Ir" (i)); | 106 | " ll %1, %2 # atomic_" #op "_return \n" \ |
107 | } else if (kernel_uses_llsc) { | 107 | " " #asm_op " %0, %1, %3 \n" \ |
108 | int temp; | 108 | " sc %0, %2 \n" \ |
109 | 109 | " .set mips0 \n" \ | |
110 | do { | 110 | : "=&r" (result), "=&r" (temp), "+m" (v->counter) \ |
111 | __asm__ __volatile__( | 111 | : "Ir" (i)); \ |
112 | " .set arch=r4000 \n" | 112 | } while (unlikely(!result)); \ |
113 | " ll %0, %1 # atomic_sub \n" | 113 | \ |
114 | " subu %0, %2 \n" | 114 | result = temp; result c_op i; \ |
115 | " sc %0, %1 \n" | 115 | } else { \ |
116 | " .set mips0 \n" | 116 | unsigned long flags; \ |
117 | : "=&r" (temp), "+m" (v->counter) | 117 | \ |
118 | : "Ir" (i)); | 118 | raw_local_irq_save(flags); \ |
119 | } while (unlikely(!temp)); | 119 | result = v->counter; \ |
120 | } else { | 120 | result c_op i; \ |
121 | unsigned long flags; | 121 | v->counter = result; \ |
122 | 122 | raw_local_irq_restore(flags); \ | |
123 | raw_local_irq_save(flags); | 123 | } \ |
124 | v->counter -= i; | 124 | \ |
125 | raw_local_irq_restore(flags); | 125 | smp_llsc_mb(); \ |
126 | } | 126 | \ |
127 | } | 127 | return result; \ |
128 | |||
129 | /* | ||
130 | * Same as above, but return the result value | ||
131 | */ | ||
132 | static __inline__ int atomic_add_return(int i, atomic_t * v) | ||
133 | { | ||
134 | int result; | ||
135 | |||
136 | smp_mb__before_llsc(); | ||
137 | |||
138 | if (kernel_uses_llsc && R10000_LLSC_WAR) { | ||
139 | int temp; | ||
140 | |||
141 | __asm__ __volatile__( | ||
142 | " .set arch=r4000 \n" | ||
143 | "1: ll %1, %2 # atomic_add_return \n" | ||
144 | " addu %0, %1, %3 \n" | ||
145 | " sc %0, %2 \n" | ||
146 | " beqzl %0, 1b \n" | ||
147 | " addu %0, %1, %3 \n" | ||
148 | " .set mips0 \n" | ||
149 | : "=&r" (result), "=&r" (temp), "+m" (v->counter) | ||
150 | : "Ir" (i)); | ||
151 | } else if (kernel_uses_llsc) { | ||
152 | int temp; | ||
153 | |||
154 | do { | ||
155 | __asm__ __volatile__( | ||
156 | " .set arch=r4000 \n" | ||
157 | " ll %1, %2 # atomic_add_return \n" | ||
158 | " addu %0, %1, %3 \n" | ||
159 | " sc %0, %2 \n" | ||
160 | " .set mips0 \n" | ||
161 | : "=&r" (result), "=&r" (temp), "+m" (v->counter) | ||
162 | : "Ir" (i)); | ||
163 | } while (unlikely(!result)); | ||
164 | |||
165 | result = temp + i; | ||
166 | } else { | ||
167 | unsigned long flags; | ||
168 | |||
169 | raw_local_irq_save(flags); | ||
170 | result = v->counter; | ||
171 | result += i; | ||
172 | v->counter = result; | ||
173 | raw_local_irq_restore(flags); | ||
174 | } | ||
175 | |||
176 | smp_llsc_mb(); | ||
177 | |||
178 | return result; | ||
179 | } | 128 | } |
180 | 129 | ||
181 | static __inline__ int atomic_sub_return(int i, atomic_t * v) | 130 | #define ATOMIC_OPS(op, c_op, asm_op) \ |
182 | { | 131 | ATOMIC_OP(op, c_op, asm_op) \ |
183 | int result; | 132 | ATOMIC_OP_RETURN(op, c_op, asm_op) |
184 | 133 | ||
185 | smp_mb__before_llsc(); | 134 | ATOMIC_OPS(add, +=, addu) |
135 | ATOMIC_OPS(sub, -=, subu) | ||
186 | 136 | ||
187 | if (kernel_uses_llsc && R10000_LLSC_WAR) { | 137 | #undef ATOMIC_OPS |
188 | int temp; | 138 | #undef ATOMIC_OP_RETURN |
189 | 139 | #undef ATOMIC_OP | |
190 | __asm__ __volatile__( | ||
191 | " .set arch=r4000 \n" | ||
192 | "1: ll %1, %2 # atomic_sub_return \n" | ||
193 | " subu %0, %1, %3 \n" | ||
194 | " sc %0, %2 \n" | ||
195 | " beqzl %0, 1b \n" | ||
196 | " subu %0, %1, %3 \n" | ||
197 | " .set mips0 \n" | ||
198 | : "=&r" (result), "=&r" (temp), "=m" (v->counter) | ||
199 | : "Ir" (i), "m" (v->counter) | ||
200 | : "memory"); | ||
201 | |||
202 | result = temp - i; | ||
203 | } else if (kernel_uses_llsc) { | ||
204 | int temp; | ||
205 | |||
206 | do { | ||
207 | __asm__ __volatile__( | ||
208 | " .set arch=r4000 \n" | ||
209 | " ll %1, %2 # atomic_sub_return \n" | ||
210 | " subu %0, %1, %3 \n" | ||
211 | " sc %0, %2 \n" | ||
212 | " .set mips0 \n" | ||
213 | : "=&r" (result), "=&r" (temp), "+m" (v->counter) | ||
214 | : "Ir" (i)); | ||
215 | } while (unlikely(!result)); | ||
216 | |||
217 | result = temp - i; | ||
218 | } else { | ||
219 | unsigned long flags; | ||
220 | |||
221 | raw_local_irq_save(flags); | ||
222 | result = v->counter; | ||
223 | result -= i; | ||
224 | v->counter = result; | ||
225 | raw_local_irq_restore(flags); | ||
226 | } | ||
227 | |||
228 | smp_llsc_mb(); | ||
229 | |||
230 | return result; | ||
231 | } | ||
232 | 140 | ||
233 | /* | 141 | /* |
234 | * atomic_sub_if_positive - conditionally subtract integer from atomic variable | 142 | * atomic_sub_if_positive - conditionally subtract integer from atomic variable |
@@ -398,7 +306,7 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) | |||
398 | * @v: pointer of type atomic64_t | 306 | * @v: pointer of type atomic64_t |
399 | * | 307 | * |
400 | */ | 308 | */ |
401 | #define atomic64_read(v) (*(volatile long *)&(v)->counter) | 309 | #define atomic64_read(v) ACCESS_ONCE((v)->counter) |
402 | 310 | ||
403 | /* | 311 | /* |
404 | * atomic64_set - set atomic variable | 312 | * atomic64_set - set atomic variable |
@@ -407,195 +315,104 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) | |||
407 | */ | 315 | */ |
408 | #define atomic64_set(v, i) ((v)->counter = (i)) | 316 | #define atomic64_set(v, i) ((v)->counter = (i)) |
409 | 317 | ||
410 | /* | 318 | #define ATOMIC64_OP(op, c_op, asm_op) \ |
411 | * atomic64_add - add integer to atomic variable | 319 | static __inline__ void atomic64_##op(long i, atomic64_t * v) \ |
412 | * @i: integer value to add | 320 | { \ |
413 | * @v: pointer of type atomic64_t | 321 | if (kernel_uses_llsc && R10000_LLSC_WAR) { \ |
414 | * | 322 | long temp; \ |
415 | * Atomically adds @i to @v. | 323 | \ |
416 | */ | 324 | __asm__ __volatile__( \ |
417 | static __inline__ void atomic64_add(long i, atomic64_t * v) | 325 | " .set arch=r4000 \n" \ |
418 | { | 326 | "1: lld %0, %1 # atomic64_" #op " \n" \ |
419 | if (kernel_uses_llsc && R10000_LLSC_WAR) { | 327 | " " #asm_op " %0, %2 \n" \ |
420 | long temp; | 328 | " scd %0, %1 \n" \ |
421 | 329 | " beqzl %0, 1b \n" \ | |
422 | __asm__ __volatile__( | 330 | " .set mips0 \n" \ |
423 | " .set arch=r4000 \n" | 331 | : "=&r" (temp), "+m" (v->counter) \ |
424 | "1: lld %0, %1 # atomic64_add \n" | 332 | : "Ir" (i)); \ |
425 | " daddu %0, %2 \n" | 333 | } else if (kernel_uses_llsc) { \ |
426 | " scd %0, %1 \n" | 334 | long temp; \ |
427 | " beqzl %0, 1b \n" | 335 | \ |
428 | " .set mips0 \n" | 336 | do { \ |
429 | : "=&r" (temp), "+m" (v->counter) | 337 | __asm__ __volatile__( \ |
430 | : "Ir" (i)); | 338 | " .set arch=r4000 \n" \ |
431 | } else if (kernel_uses_llsc) { | 339 | " lld %0, %1 # atomic64_" #op "\n" \ |
432 | long temp; | 340 | " " #asm_op " %0, %2 \n" \ |
433 | 341 | " scd %0, %1 \n" \ | |
434 | do { | 342 | " .set mips0 \n" \ |
435 | __asm__ __volatile__( | 343 | : "=&r" (temp), "+m" (v->counter) \ |
436 | " .set arch=r4000 \n" | 344 | : "Ir" (i)); \ |
437 | " lld %0, %1 # atomic64_add \n" | 345 | } while (unlikely(!temp)); \ |
438 | " daddu %0, %2 \n" | 346 | } else { \ |
439 | " scd %0, %1 \n" | 347 | unsigned long flags; \ |
440 | " .set mips0 \n" | 348 | \ |
441 | : "=&r" (temp), "+m" (v->counter) | 349 | raw_local_irq_save(flags); \ |
442 | : "Ir" (i)); | 350 | v->counter c_op i; \ |
443 | } while (unlikely(!temp)); | 351 | raw_local_irq_restore(flags); \ |
444 | } else { | 352 | } \ |
445 | unsigned long flags; | 353 | } \ |
446 | 354 | ||
447 | raw_local_irq_save(flags); | 355 | #define ATOMIC64_OP_RETURN(op, c_op, asm_op) \ |
448 | v->counter += i; | 356 | static __inline__ long atomic64_##op##_return(long i, atomic64_t * v) \ |
449 | raw_local_irq_restore(flags); | 357 | { \ |
450 | } | 358 | long result; \ |
359 | \ | ||
360 | smp_mb__before_llsc(); \ | ||
361 | \ | ||
362 | if (kernel_uses_llsc && R10000_LLSC_WAR) { \ | ||
363 | long temp; \ | ||
364 | \ | ||
365 | __asm__ __volatile__( \ | ||
366 | " .set arch=r4000 \n" \ | ||
367 | "1: lld %1, %2 # atomic64_" #op "_return\n" \ | ||
368 | " " #asm_op " %0, %1, %3 \n" \ | ||
369 | " scd %0, %2 \n" \ | ||
370 | " beqzl %0, 1b \n" \ | ||
371 | " " #asm_op " %0, %1, %3 \n" \ | ||
372 | " .set mips0 \n" \ | ||
373 | : "=&r" (result), "=&r" (temp), "+m" (v->counter) \ | ||
374 | : "Ir" (i)); \ | ||
375 | } else if (kernel_uses_llsc) { \ | ||
376 | long temp; \ | ||
377 | \ | ||
378 | do { \ | ||
379 | __asm__ __volatile__( \ | ||
380 | " .set arch=r4000 \n" \ | ||
381 | " lld %1, %2 # atomic64_" #op "_return\n" \ | ||
382 | " " #asm_op " %0, %1, %3 \n" \ | ||
383 | " scd %0, %2 \n" \ | ||
384 | " .set mips0 \n" \ | ||
385 | : "=&r" (result), "=&r" (temp), "=m" (v->counter) \ | ||
386 | : "Ir" (i), "m" (v->counter) \ | ||
387 | : "memory"); \ | ||
388 | } while (unlikely(!result)); \ | ||
389 | \ | ||
390 | result = temp; result c_op i; \ | ||
391 | } else { \ | ||
392 | unsigned long flags; \ | ||
393 | \ | ||
394 | raw_local_irq_save(flags); \ | ||
395 | result = v->counter; \ | ||
396 | result c_op i; \ | ||
397 | v->counter = result; \ | ||
398 | raw_local_irq_restore(flags); \ | ||
399 | } \ | ||
400 | \ | ||
401 | smp_llsc_mb(); \ | ||
402 | \ | ||
403 | return result; \ | ||
451 | } | 404 | } |
452 | 405 | ||
453 | /* | 406 | #define ATOMIC64_OPS(op, c_op, asm_op) \ |
454 | * atomic64_sub - subtract the atomic variable | 407 | ATOMIC64_OP(op, c_op, asm_op) \ |
455 | * @i: integer value to subtract | 408 | ATOMIC64_OP_RETURN(op, c_op, asm_op) |
456 | * @v: pointer of type atomic64_t | ||
457 | * | ||
458 | * Atomically subtracts @i from @v. | ||
459 | */ | ||
460 | static __inline__ void atomic64_sub(long i, atomic64_t * v) | ||
461 | { | ||
462 | if (kernel_uses_llsc && R10000_LLSC_WAR) { | ||
463 | long temp; | ||
464 | |||
465 | __asm__ __volatile__( | ||
466 | " .set arch=r4000 \n" | ||
467 | "1: lld %0, %1 # atomic64_sub \n" | ||
468 | " dsubu %0, %2 \n" | ||
469 | " scd %0, %1 \n" | ||
470 | " beqzl %0, 1b \n" | ||
471 | " .set mips0 \n" | ||
472 | : "=&r" (temp), "+m" (v->counter) | ||
473 | : "Ir" (i)); | ||
474 | } else if (kernel_uses_llsc) { | ||
475 | long temp; | ||
476 | |||
477 | do { | ||
478 | __asm__ __volatile__( | ||
479 | " .set arch=r4000 \n" | ||
480 | " lld %0, %1 # atomic64_sub \n" | ||
481 | " dsubu %0, %2 \n" | ||
482 | " scd %0, %1 \n" | ||
483 | " .set mips0 \n" | ||
484 | : "=&r" (temp), "+m" (v->counter) | ||
485 | : "Ir" (i)); | ||
486 | } while (unlikely(!temp)); | ||
487 | } else { | ||
488 | unsigned long flags; | ||
489 | |||
490 | raw_local_irq_save(flags); | ||
491 | v->counter -= i; | ||
492 | raw_local_irq_restore(flags); | ||
493 | } | ||
494 | } | ||
495 | |||
496 | /* | ||
497 | * Same as above, but return the result value | ||
498 | */ | ||
499 | static __inline__ long atomic64_add_return(long i, atomic64_t * v) | ||
500 | { | ||
501 | long result; | ||
502 | 409 | ||
503 | smp_mb__before_llsc(); | 410 | ATOMIC64_OPS(add, +=, daddu) |
411 | ATOMIC64_OPS(sub, -=, dsubu) | ||
504 | 412 | ||
505 | if (kernel_uses_llsc && R10000_LLSC_WAR) { | 413 | #undef ATOMIC64_OPS |
506 | long temp; | 414 | #undef ATOMIC64_OP_RETURN |
507 | 415 | #undef ATOMIC64_OP | |
508 | __asm__ __volatile__( | ||
509 | " .set arch=r4000 \n" | ||
510 | "1: lld %1, %2 # atomic64_add_return \n" | ||
511 | " daddu %0, %1, %3 \n" | ||
512 | " scd %0, %2 \n" | ||
513 | " beqzl %0, 1b \n" | ||
514 | " daddu %0, %1, %3 \n" | ||
515 | " .set mips0 \n" | ||
516 | : "=&r" (result), "=&r" (temp), "+m" (v->counter) | ||
517 | : "Ir" (i)); | ||
518 | } else if (kernel_uses_llsc) { | ||
519 | long temp; | ||
520 | |||
521 | do { | ||
522 | __asm__ __volatile__( | ||
523 | " .set arch=r4000 \n" | ||
524 | " lld %1, %2 # atomic64_add_return \n" | ||
525 | " daddu %0, %1, %3 \n" | ||
526 | " scd %0, %2 \n" | ||
527 | " .set mips0 \n" | ||
528 | : "=&r" (result), "=&r" (temp), "=m" (v->counter) | ||
529 | : "Ir" (i), "m" (v->counter) | ||
530 | : "memory"); | ||
531 | } while (unlikely(!result)); | ||
532 | |||
533 | result = temp + i; | ||
534 | } else { | ||
535 | unsigned long flags; | ||
536 | |||
537 | raw_local_irq_save(flags); | ||
538 | result = v->counter; | ||
539 | result += i; | ||
540 | v->counter = result; | ||
541 | raw_local_irq_restore(flags); | ||
542 | } | ||
543 | |||
544 | smp_llsc_mb(); | ||
545 | |||
546 | return result; | ||
547 | } | ||
548 | |||
549 | static __inline__ long atomic64_sub_return(long i, atomic64_t * v) | ||
550 | { | ||
551 | long result; | ||
552 | |||
553 | smp_mb__before_llsc(); | ||
554 | |||
555 | if (kernel_uses_llsc && R10000_LLSC_WAR) { | ||
556 | long temp; | ||
557 | |||
558 | __asm__ __volatile__( | ||
559 | " .set arch=r4000 \n" | ||
560 | "1: lld %1, %2 # atomic64_sub_return \n" | ||
561 | " dsubu %0, %1, %3 \n" | ||
562 | " scd %0, %2 \n" | ||
563 | " beqzl %0, 1b \n" | ||
564 | " dsubu %0, %1, %3 \n" | ||
565 | " .set mips0 \n" | ||
566 | : "=&r" (result), "=&r" (temp), "=m" (v->counter) | ||
567 | : "Ir" (i), "m" (v->counter) | ||
568 | : "memory"); | ||
569 | } else if (kernel_uses_llsc) { | ||
570 | long temp; | ||
571 | |||
572 | do { | ||
573 | __asm__ __volatile__( | ||
574 | " .set arch=r4000 \n" | ||
575 | " lld %1, %2 # atomic64_sub_return \n" | ||
576 | " dsubu %0, %1, %3 \n" | ||
577 | " scd %0, %2 \n" | ||
578 | " .set mips0 \n" | ||
579 | : "=&r" (result), "=&r" (temp), "=m" (v->counter) | ||
580 | : "Ir" (i), "m" (v->counter) | ||
581 | : "memory"); | ||
582 | } while (unlikely(!result)); | ||
583 | |||
584 | result = temp - i; | ||
585 | } else { | ||
586 | unsigned long flags; | ||
587 | |||
588 | raw_local_irq_save(flags); | ||
589 | result = v->counter; | ||
590 | result -= i; | ||
591 | v->counter = result; | ||
592 | raw_local_irq_restore(flags); | ||
593 | } | ||
594 | |||
595 | smp_llsc_mb(); | ||
596 | |||
597 | return result; | ||
598 | } | ||
599 | 416 | ||
600 | /* | 417 | /* |
601 | * atomic64_sub_if_positive - conditionally subtract integer from atomic variable | 418 | * atomic64_sub_if_positive - conditionally subtract integer from atomic variable |
diff --git a/arch/mn10300/include/asm/atomic.h b/arch/mn10300/include/asm/atomic.h index cadeb1e2cdfc..5be655e83e70 100644 --- a/arch/mn10300/include/asm/atomic.h +++ b/arch/mn10300/include/asm/atomic.h | |||
@@ -33,7 +33,6 @@ | |||
33 | * @v: pointer of type atomic_t | 33 | * @v: pointer of type atomic_t |
34 | * | 34 | * |
35 | * Atomically reads the value of @v. Note that the guaranteed | 35 | * Atomically reads the value of @v. Note that the guaranteed |
36 | * useful range of an atomic_t is only 24 bits. | ||
37 | */ | 36 | */ |
38 | #define atomic_read(v) (ACCESS_ONCE((v)->counter)) | 37 | #define atomic_read(v) (ACCESS_ONCE((v)->counter)) |
39 | 38 | ||
@@ -43,102 +42,62 @@ | |||
43 | * @i: required value | 42 | * @i: required value |
44 | * | 43 | * |
45 | * Atomically sets the value of @v to @i. Note that the guaranteed | 44 | * Atomically sets the value of @v to @i. Note that the guaranteed |
46 | * useful range of an atomic_t is only 24 bits. | ||
47 | */ | 45 | */ |
48 | #define atomic_set(v, i) (((v)->counter) = (i)) | 46 | #define atomic_set(v, i) (((v)->counter) = (i)) |
49 | 47 | ||
50 | /** | 48 | #define ATOMIC_OP(op) \ |
51 | * atomic_add_return - add integer to atomic variable | 49 | static inline void atomic_##op(int i, atomic_t *v) \ |
52 | * @i: integer value to add | 50 | { \ |
53 | * @v: pointer of type atomic_t | 51 | int retval, status; \ |
54 | * | 52 | \ |
55 | * Atomically adds @i to @v and returns the result | 53 | asm volatile( \ |
56 | * Note that the guaranteed useful range of an atomic_t is only 24 bits. | 54 | "1: mov %4,(_AAR,%3) \n" \ |
57 | */ | 55 | " mov (_ADR,%3),%1 \n" \ |
58 | static inline int atomic_add_return(int i, atomic_t *v) | 56 | " " #op " %5,%1 \n" \ |
59 | { | 57 | " mov %1,(_ADR,%3) \n" \ |
60 | int retval; | 58 | " mov (_ADR,%3),%0 \n" /* flush */ \ |
61 | #ifdef CONFIG_SMP | 59 | " mov (_ASR,%3),%0 \n" \ |
62 | int status; | 60 | " or %0,%0 \n" \ |
63 | 61 | " bne 1b \n" \ | |
64 | asm volatile( | 62 | : "=&r"(status), "=&r"(retval), "=m"(v->counter) \ |
65 | "1: mov %4,(_AAR,%3) \n" | 63 | : "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i) \ |
66 | " mov (_ADR,%3),%1 \n" | 64 | : "memory", "cc"); \ |
67 | " add %5,%1 \n" | 65 | } |
68 | " mov %1,(_ADR,%3) \n" | ||
69 | " mov (_ADR,%3),%0 \n" /* flush */ | ||
70 | " mov (_ASR,%3),%0 \n" | ||
71 | " or %0,%0 \n" | ||
72 | " bne 1b \n" | ||
73 | : "=&r"(status), "=&r"(retval), "=m"(v->counter) | ||
74 | : "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i) | ||
75 | : "memory", "cc"); | ||
76 | |||
77 | #else | ||
78 | unsigned long flags; | ||
79 | 66 | ||
80 | flags = arch_local_cli_save(); | 67 | #define ATOMIC_OP_RETURN(op) \ |
81 | retval = v->counter; | 68 | static inline int atomic_##op##_return(int i, atomic_t *v) \ |
82 | retval += i; | 69 | { \ |
83 | v->counter = retval; | 70 | int retval, status; \ |
84 | arch_local_irq_restore(flags); | 71 | \ |
85 | #endif | 72 | asm volatile( \ |
86 | return retval; | 73 | "1: mov %4,(_AAR,%3) \n" \ |
74 | " mov (_ADR,%3),%1 \n" \ | ||
75 | " " #op " %5,%1 \n" \ | ||
76 | " mov %1,(_ADR,%3) \n" \ | ||
77 | " mov (_ADR,%3),%0 \n" /* flush */ \ | ||
78 | " mov (_ASR,%3),%0 \n" \ | ||
79 | " or %0,%0 \n" \ | ||
80 | " bne 1b \n" \ | ||
81 | : "=&r"(status), "=&r"(retval), "=m"(v->counter) \ | ||
82 | : "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i) \ | ||
83 | : "memory", "cc"); \ | ||
84 | return retval; \ | ||
87 | } | 85 | } |
88 | 86 | ||
89 | /** | 87 | #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) |
90 | * atomic_sub_return - subtract integer from atomic variable | ||
91 | * @i: integer value to subtract | ||
92 | * @v: pointer of type atomic_t | ||
93 | * | ||
94 | * Atomically subtracts @i from @v and returns the result | ||
95 | * Note that the guaranteed useful range of an atomic_t is only 24 bits. | ||
96 | */ | ||
97 | static inline int atomic_sub_return(int i, atomic_t *v) | ||
98 | { | ||
99 | int retval; | ||
100 | #ifdef CONFIG_SMP | ||
101 | int status; | ||
102 | 88 | ||
103 | asm volatile( | 89 | ATOMIC_OPS(add) |
104 | "1: mov %4,(_AAR,%3) \n" | 90 | ATOMIC_OPS(sub) |
105 | " mov (_ADR,%3),%1 \n" | ||
106 | " sub %5,%1 \n" | ||
107 | " mov %1,(_ADR,%3) \n" | ||
108 | " mov (_ADR,%3),%0 \n" /* flush */ | ||
109 | " mov (_ASR,%3),%0 \n" | ||
110 | " or %0,%0 \n" | ||
111 | " bne 1b \n" | ||
112 | : "=&r"(status), "=&r"(retval), "=m"(v->counter) | ||
113 | : "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i) | ||
114 | : "memory", "cc"); | ||
115 | 91 | ||
116 | #else | 92 | #undef ATOMIC_OPS |
117 | unsigned long flags; | 93 | #undef ATOMIC_OP_RETURN |
118 | flags = arch_local_cli_save(); | 94 | #undef ATOMIC_OP |
119 | retval = v->counter; | ||
120 | retval -= i; | ||
121 | v->counter = retval; | ||
122 | arch_local_irq_restore(flags); | ||
123 | #endif | ||
124 | return retval; | ||
125 | } | ||
126 | 95 | ||
127 | static inline int atomic_add_negative(int i, atomic_t *v) | 96 | static inline int atomic_add_negative(int i, atomic_t *v) |
128 | { | 97 | { |
129 | return atomic_add_return(i, v) < 0; | 98 | return atomic_add_return(i, v) < 0; |
130 | } | 99 | } |
131 | 100 | ||
132 | static inline void atomic_add(int i, atomic_t *v) | ||
133 | { | ||
134 | atomic_add_return(i, v); | ||
135 | } | ||
136 | |||
137 | static inline void atomic_sub(int i, atomic_t *v) | ||
138 | { | ||
139 | atomic_sub_return(i, v); | ||
140 | } | ||
141 | |||
142 | static inline void atomic_inc(atomic_t *v) | 101 | static inline void atomic_inc(atomic_t *v) |
143 | { | 102 | { |
144 | atomic_add_return(1, v); | 103 | atomic_add_return(1, v); |
diff --git a/arch/parisc/include/asm/atomic.h b/arch/parisc/include/asm/atomic.h index 0be2db2c7d44..226f8ca993f6 100644 --- a/arch/parisc/include/asm/atomic.h +++ b/arch/parisc/include/asm/atomic.h | |||
@@ -55,24 +55,7 @@ extern arch_spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned; | |||
55 | * are atomic, so a reader never sees inconsistent values. | 55 | * are atomic, so a reader never sees inconsistent values. |
56 | */ | 56 | */ |
57 | 57 | ||
58 | /* It's possible to reduce all atomic operations to either | 58 | static __inline__ void atomic_set(atomic_t *v, int i) |
59 | * __atomic_add_return, atomic_set and atomic_read (the latter | ||
60 | * is there only for consistency). | ||
61 | */ | ||
62 | |||
63 | static __inline__ int __atomic_add_return(int i, atomic_t *v) | ||
64 | { | ||
65 | int ret; | ||
66 | unsigned long flags; | ||
67 | _atomic_spin_lock_irqsave(v, flags); | ||
68 | |||
69 | ret = (v->counter += i); | ||
70 | |||
71 | _atomic_spin_unlock_irqrestore(v, flags); | ||
72 | return ret; | ||
73 | } | ||
74 | |||
75 | static __inline__ void atomic_set(atomic_t *v, int i) | ||
76 | { | 59 | { |
77 | unsigned long flags; | 60 | unsigned long flags; |
78 | _atomic_spin_lock_irqsave(v, flags); | 61 | _atomic_spin_lock_irqsave(v, flags); |
@@ -84,7 +67,7 @@ static __inline__ void atomic_set(atomic_t *v, int i) | |||
84 | 67 | ||
85 | static __inline__ int atomic_read(const atomic_t *v) | 68 | static __inline__ int atomic_read(const atomic_t *v) |
86 | { | 69 | { |
87 | return (*(volatile int *)&(v)->counter); | 70 | return ACCESS_ONCE((v)->counter); |
88 | } | 71 | } |
89 | 72 | ||
90 | /* exported interface */ | 73 | /* exported interface */ |
@@ -115,16 +98,43 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) | |||
115 | return c; | 98 | return c; |
116 | } | 99 | } |
117 | 100 | ||
101 | #define ATOMIC_OP(op, c_op) \ | ||
102 | static __inline__ void atomic_##op(int i, atomic_t *v) \ | ||
103 | { \ | ||
104 | unsigned long flags; \ | ||
105 | \ | ||
106 | _atomic_spin_lock_irqsave(v, flags); \ | ||
107 | v->counter c_op i; \ | ||
108 | _atomic_spin_unlock_irqrestore(v, flags); \ | ||
109 | } \ | ||
110 | |||
111 | #define ATOMIC_OP_RETURN(op, c_op) \ | ||
112 | static __inline__ int atomic_##op##_return(int i, atomic_t *v) \ | ||
113 | { \ | ||
114 | unsigned long flags; \ | ||
115 | int ret; \ | ||
116 | \ | ||
117 | _atomic_spin_lock_irqsave(v, flags); \ | ||
118 | ret = (v->counter c_op i); \ | ||
119 | _atomic_spin_unlock_irqrestore(v, flags); \ | ||
120 | \ | ||
121 | return ret; \ | ||
122 | } | ||
123 | |||
124 | #define ATOMIC_OPS(op, c_op) ATOMIC_OP(op, c_op) ATOMIC_OP_RETURN(op, c_op) | ||
125 | |||
126 | ATOMIC_OPS(add, +=) | ||
127 | ATOMIC_OPS(sub, -=) | ||
128 | |||
129 | #undef ATOMIC_OPS | ||
130 | #undef ATOMIC_OP_RETURN | ||
131 | #undef ATOMIC_OP | ||
118 | 132 | ||
119 | #define atomic_add(i,v) ((void)(__atomic_add_return( (i),(v)))) | 133 | #define atomic_inc(v) (atomic_add( 1,(v))) |
120 | #define atomic_sub(i,v) ((void)(__atomic_add_return(-((int) (i)),(v)))) | 134 | #define atomic_dec(v) (atomic_add( -1,(v))) |
121 | #define atomic_inc(v) ((void)(__atomic_add_return( 1,(v)))) | ||
122 | #define atomic_dec(v) ((void)(__atomic_add_return( -1,(v)))) | ||
123 | 135 | ||
124 | #define atomic_add_return(i,v) (__atomic_add_return( (i),(v))) | 136 | #define atomic_inc_return(v) (atomic_add_return( 1,(v))) |
125 | #define atomic_sub_return(i,v) (__atomic_add_return(-(i),(v))) | 137 | #define atomic_dec_return(v) (atomic_add_return( -1,(v))) |
126 | #define atomic_inc_return(v) (__atomic_add_return( 1,(v))) | ||
127 | #define atomic_dec_return(v) (__atomic_add_return( -1,(v))) | ||
128 | 138 | ||
129 | #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) | 139 | #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) |
130 | 140 | ||
@@ -148,18 +158,37 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) | |||
148 | 158 | ||
149 | #define ATOMIC64_INIT(i) { (i) } | 159 | #define ATOMIC64_INIT(i) { (i) } |
150 | 160 | ||
151 | static __inline__ s64 | 161 | #define ATOMIC64_OP(op, c_op) \ |
152 | __atomic64_add_return(s64 i, atomic64_t *v) | 162 | static __inline__ void atomic64_##op(s64 i, atomic64_t *v) \ |
153 | { | 163 | { \ |
154 | s64 ret; | 164 | unsigned long flags; \ |
155 | unsigned long flags; | 165 | \ |
156 | _atomic_spin_lock_irqsave(v, flags); | 166 | _atomic_spin_lock_irqsave(v, flags); \ |
167 | v->counter c_op i; \ | ||
168 | _atomic_spin_unlock_irqrestore(v, flags); \ | ||
169 | } \ | ||
170 | |||
171 | #define ATOMIC64_OP_RETURN(op, c_op) \ | ||
172 | static __inline__ s64 atomic64_##op##_return(s64 i, atomic64_t *v) \ | ||
173 | { \ | ||
174 | unsigned long flags; \ | ||
175 | s64 ret; \ | ||
176 | \ | ||
177 | _atomic_spin_lock_irqsave(v, flags); \ | ||
178 | ret = (v->counter c_op i); \ | ||
179 | _atomic_spin_unlock_irqrestore(v, flags); \ | ||
180 | \ | ||
181 | return ret; \ | ||
182 | } | ||
157 | 183 | ||
158 | ret = (v->counter += i); | 184 | #define ATOMIC64_OPS(op, c_op) ATOMIC64_OP(op, c_op) ATOMIC64_OP_RETURN(op, c_op) |
159 | 185 | ||
160 | _atomic_spin_unlock_irqrestore(v, flags); | 186 | ATOMIC64_OPS(add, +=) |
161 | return ret; | 187 | ATOMIC64_OPS(sub, -=) |
162 | } | 188 | |
189 | #undef ATOMIC64_OPS | ||
190 | #undef ATOMIC64_OP_RETURN | ||
191 | #undef ATOMIC64_OP | ||
163 | 192 | ||
164 | static __inline__ void | 193 | static __inline__ void |
165 | atomic64_set(atomic64_t *v, s64 i) | 194 | atomic64_set(atomic64_t *v, s64 i) |
@@ -175,18 +204,14 @@ atomic64_set(atomic64_t *v, s64 i) | |||
175 | static __inline__ s64 | 204 | static __inline__ s64 |
176 | atomic64_read(const atomic64_t *v) | 205 | atomic64_read(const atomic64_t *v) |
177 | { | 206 | { |
178 | return (*(volatile long *)&(v)->counter); | 207 | return ACCESS_ONCE((v)->counter); |
179 | } | 208 | } |
180 | 209 | ||
181 | #define atomic64_add(i,v) ((void)(__atomic64_add_return( ((s64)(i)),(v)))) | 210 | #define atomic64_inc(v) (atomic64_add( 1,(v))) |
182 | #define atomic64_sub(i,v) ((void)(__atomic64_add_return(-((s64)(i)),(v)))) | 211 | #define atomic64_dec(v) (atomic64_add( -1,(v))) |
183 | #define atomic64_inc(v) ((void)(__atomic64_add_return( 1,(v)))) | ||
184 | #define atomic64_dec(v) ((void)(__atomic64_add_return( -1,(v)))) | ||
185 | 212 | ||
186 | #define atomic64_add_return(i,v) (__atomic64_add_return( ((s64)(i)),(v))) | 213 | #define atomic64_inc_return(v) (atomic64_add_return( 1,(v))) |
187 | #define atomic64_sub_return(i,v) (__atomic64_add_return(-((s64)(i)),(v))) | 214 | #define atomic64_dec_return(v) (atomic64_add_return( -1,(v))) |
188 | #define atomic64_inc_return(v) (__atomic64_add_return( 1,(v))) | ||
189 | #define atomic64_dec_return(v) (__atomic64_add_return( -1,(v))) | ||
190 | 215 | ||
191 | #define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0) | 216 | #define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0) |
192 | 217 | ||
diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h index 28992d012926..512d2782b043 100644 --- a/arch/powerpc/include/asm/atomic.h +++ b/arch/powerpc/include/asm/atomic.h | |||
@@ -26,76 +26,53 @@ static __inline__ void atomic_set(atomic_t *v, int i) | |||
26 | __asm__ __volatile__("stw%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i)); | 26 | __asm__ __volatile__("stw%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i)); |
27 | } | 27 | } |
28 | 28 | ||
29 | static __inline__ void atomic_add(int a, atomic_t *v) | 29 | #define ATOMIC_OP(op, asm_op) \ |
30 | { | 30 | static __inline__ void atomic_##op(int a, atomic_t *v) \ |
31 | int t; | 31 | { \ |
32 | 32 | int t; \ | |
33 | __asm__ __volatile__( | 33 | \ |
34 | "1: lwarx %0,0,%3 # atomic_add\n\ | 34 | __asm__ __volatile__( \ |
35 | add %0,%2,%0\n" | 35 | "1: lwarx %0,0,%3 # atomic_" #op "\n" \ |
36 | PPC405_ERR77(0,%3) | 36 | #asm_op " %0,%2,%0\n" \ |
37 | " stwcx. %0,0,%3 \n\ | 37 | PPC405_ERR77(0,%3) \ |
38 | bne- 1b" | 38 | " stwcx. %0,0,%3 \n" \ |
39 | : "=&r" (t), "+m" (v->counter) | 39 | " bne- 1b\n" \ |
40 | : "r" (a), "r" (&v->counter) | 40 | : "=&r" (t), "+m" (v->counter) \ |
41 | : "cc"); | 41 | : "r" (a), "r" (&v->counter) \ |
42 | : "cc"); \ | ||
43 | } \ | ||
44 | |||
45 | #define ATOMIC_OP_RETURN(op, asm_op) \ | ||
46 | static __inline__ int atomic_##op##_return(int a, atomic_t *v) \ | ||
47 | { \ | ||
48 | int t; \ | ||
49 | \ | ||
50 | __asm__ __volatile__( \ | ||
51 | PPC_ATOMIC_ENTRY_BARRIER \ | ||
52 | "1: lwarx %0,0,%2 # atomic_" #op "_return\n" \ | ||
53 | #asm_op " %0,%1,%0\n" \ | ||
54 | PPC405_ERR77(0,%2) \ | ||
55 | " stwcx. %0,0,%2 \n" \ | ||
56 | " bne- 1b\n" \ | ||
57 | PPC_ATOMIC_EXIT_BARRIER \ | ||
58 | : "=&r" (t) \ | ||
59 | : "r" (a), "r" (&v->counter) \ | ||
60 | : "cc", "memory"); \ | ||
61 | \ | ||
62 | return t; \ | ||
42 | } | 63 | } |
43 | 64 | ||
44 | static __inline__ int atomic_add_return(int a, atomic_t *v) | 65 | #define ATOMIC_OPS(op, asm_op) ATOMIC_OP(op, asm_op) ATOMIC_OP_RETURN(op, asm_op) |
45 | { | ||
46 | int t; | ||
47 | 66 | ||
48 | __asm__ __volatile__( | 67 | ATOMIC_OPS(add, add) |
49 | PPC_ATOMIC_ENTRY_BARRIER | 68 | ATOMIC_OPS(sub, subf) |
50 | "1: lwarx %0,0,%2 # atomic_add_return\n\ | ||
51 | add %0,%1,%0\n" | ||
52 | PPC405_ERR77(0,%2) | ||
53 | " stwcx. %0,0,%2 \n\ | ||
54 | bne- 1b" | ||
55 | PPC_ATOMIC_EXIT_BARRIER | ||
56 | : "=&r" (t) | ||
57 | : "r" (a), "r" (&v->counter) | ||
58 | : "cc", "memory"); | ||
59 | 69 | ||
60 | return t; | 70 | #undef ATOMIC_OPS |
61 | } | 71 | #undef ATOMIC_OP_RETURN |
72 | #undef ATOMIC_OP | ||
62 | 73 | ||
63 | #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) | 74 | #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) |
64 | 75 | ||
65 | static __inline__ void atomic_sub(int a, atomic_t *v) | ||
66 | { | ||
67 | int t; | ||
68 | |||
69 | __asm__ __volatile__( | ||
70 | "1: lwarx %0,0,%3 # atomic_sub\n\ | ||
71 | subf %0,%2,%0\n" | ||
72 | PPC405_ERR77(0,%3) | ||
73 | " stwcx. %0,0,%3 \n\ | ||
74 | bne- 1b" | ||
75 | : "=&r" (t), "+m" (v->counter) | ||
76 | : "r" (a), "r" (&v->counter) | ||
77 | : "cc"); | ||
78 | } | ||
79 | |||
80 | static __inline__ int atomic_sub_return(int a, atomic_t *v) | ||
81 | { | ||
82 | int t; | ||
83 | |||
84 | __asm__ __volatile__( | ||
85 | PPC_ATOMIC_ENTRY_BARRIER | ||
86 | "1: lwarx %0,0,%2 # atomic_sub_return\n\ | ||
87 | subf %0,%1,%0\n" | ||
88 | PPC405_ERR77(0,%2) | ||
89 | " stwcx. %0,0,%2 \n\ | ||
90 | bne- 1b" | ||
91 | PPC_ATOMIC_EXIT_BARRIER | ||
92 | : "=&r" (t) | ||
93 | : "r" (a), "r" (&v->counter) | ||
94 | : "cc", "memory"); | ||
95 | |||
96 | return t; | ||
97 | } | ||
98 | |||
99 | static __inline__ void atomic_inc(atomic_t *v) | 76 | static __inline__ void atomic_inc(atomic_t *v) |
100 | { | 77 | { |
101 | int t; | 78 | int t; |
@@ -289,71 +266,50 @@ static __inline__ void atomic64_set(atomic64_t *v, long i) | |||
289 | __asm__ __volatile__("std%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i)); | 266 | __asm__ __volatile__("std%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i)); |
290 | } | 267 | } |
291 | 268 | ||
292 | static __inline__ void atomic64_add(long a, atomic64_t *v) | 269 | #define ATOMIC64_OP(op, asm_op) \ |
293 | { | 270 | static __inline__ void atomic64_##op(long a, atomic64_t *v) \ |
294 | long t; | 271 | { \ |
295 | 272 | long t; \ | |
296 | __asm__ __volatile__( | 273 | \ |
297 | "1: ldarx %0,0,%3 # atomic64_add\n\ | 274 | __asm__ __volatile__( \ |
298 | add %0,%2,%0\n\ | 275 | "1: ldarx %0,0,%3 # atomic64_" #op "\n" \ |
299 | stdcx. %0,0,%3 \n\ | 276 | #asm_op " %0,%2,%0\n" \ |
300 | bne- 1b" | 277 | " stdcx. %0,0,%3 \n" \ |
301 | : "=&r" (t), "+m" (v->counter) | 278 | " bne- 1b\n" \ |
302 | : "r" (a), "r" (&v->counter) | 279 | : "=&r" (t), "+m" (v->counter) \ |
303 | : "cc"); | 280 | : "r" (a), "r" (&v->counter) \ |
281 | : "cc"); \ | ||
304 | } | 282 | } |
305 | 283 | ||
306 | static __inline__ long atomic64_add_return(long a, atomic64_t *v) | 284 | #define ATOMIC64_OP_RETURN(op, asm_op) \ |
307 | { | 285 | static __inline__ long atomic64_##op##_return(long a, atomic64_t *v) \ |
308 | long t; | 286 | { \ |
309 | 287 | long t; \ | |
310 | __asm__ __volatile__( | 288 | \ |
311 | PPC_ATOMIC_ENTRY_BARRIER | 289 | __asm__ __volatile__( \ |
312 | "1: ldarx %0,0,%2 # atomic64_add_return\n\ | 290 | PPC_ATOMIC_ENTRY_BARRIER \ |
313 | add %0,%1,%0\n\ | 291 | "1: ldarx %0,0,%2 # atomic64_" #op "_return\n" \ |
314 | stdcx. %0,0,%2 \n\ | 292 | #asm_op " %0,%1,%0\n" \ |
315 | bne- 1b" | 293 | " stdcx. %0,0,%2 \n" \ |
316 | PPC_ATOMIC_EXIT_BARRIER | 294 | " bne- 1b\n" \ |
317 | : "=&r" (t) | 295 | PPC_ATOMIC_EXIT_BARRIER \ |
318 | : "r" (a), "r" (&v->counter) | 296 | : "=&r" (t) \ |
319 | : "cc", "memory"); | 297 | : "r" (a), "r" (&v->counter) \ |
320 | 298 | : "cc", "memory"); \ | |
321 | return t; | 299 | \ |
300 | return t; \ | ||
322 | } | 301 | } |
323 | 302 | ||
324 | #define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0) | 303 | #define ATOMIC64_OPS(op, asm_op) ATOMIC64_OP(op, asm_op) ATOMIC64_OP_RETURN(op, asm_op) |
325 | |||
326 | static __inline__ void atomic64_sub(long a, atomic64_t *v) | ||
327 | { | ||
328 | long t; | ||
329 | |||
330 | __asm__ __volatile__( | ||
331 | "1: ldarx %0,0,%3 # atomic64_sub\n\ | ||
332 | subf %0,%2,%0\n\ | ||
333 | stdcx. %0,0,%3 \n\ | ||
334 | bne- 1b" | ||
335 | : "=&r" (t), "+m" (v->counter) | ||
336 | : "r" (a), "r" (&v->counter) | ||
337 | : "cc"); | ||
338 | } | ||
339 | 304 | ||
340 | static __inline__ long atomic64_sub_return(long a, atomic64_t *v) | 305 | ATOMIC64_OPS(add, add) |
341 | { | 306 | ATOMIC64_OPS(sub, subf) |
342 | long t; | ||
343 | 307 | ||
344 | __asm__ __volatile__( | 308 | #undef ATOMIC64_OPS |
345 | PPC_ATOMIC_ENTRY_BARRIER | 309 | #undef ATOMIC64_OP_RETURN |
346 | "1: ldarx %0,0,%2 # atomic64_sub_return\n\ | 310 | #undef ATOMIC64_OP |
347 | subf %0,%1,%0\n\ | ||
348 | stdcx. %0,0,%2 \n\ | ||
349 | bne- 1b" | ||
350 | PPC_ATOMIC_EXIT_BARRIER | ||
351 | : "=&r" (t) | ||
352 | : "r" (a), "r" (&v->counter) | ||
353 | : "cc", "memory"); | ||
354 | 311 | ||
355 | return t; | 312 | #define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0) |
356 | } | ||
357 | 313 | ||
358 | static __inline__ void atomic64_inc(atomic64_t *v) | 314 | static __inline__ void atomic64_inc(atomic64_t *v) |
359 | { | 315 | { |
diff --git a/arch/sh/include/asm/atomic-grb.h b/arch/sh/include/asm/atomic-grb.h index a273c88578fc..97a5fda83450 100644 --- a/arch/sh/include/asm/atomic-grb.h +++ b/arch/sh/include/asm/atomic-grb.h | |||
@@ -1,85 +1,56 @@ | |||
1 | #ifndef __ASM_SH_ATOMIC_GRB_H | 1 | #ifndef __ASM_SH_ATOMIC_GRB_H |
2 | #define __ASM_SH_ATOMIC_GRB_H | 2 | #define __ASM_SH_ATOMIC_GRB_H |
3 | 3 | ||
4 | static inline void atomic_add(int i, atomic_t *v) | 4 | #define ATOMIC_OP(op) \ |
5 | { | 5 | static inline void atomic_##op(int i, atomic_t *v) \ |
6 | int tmp; | 6 | { \ |
7 | 7 | int tmp; \ | |
8 | __asm__ __volatile__ ( | 8 | \ |
9 | " .align 2 \n\t" | 9 | __asm__ __volatile__ ( \ |
10 | " mova 1f, r0 \n\t" /* r0 = end point */ | 10 | " .align 2 \n\t" \ |
11 | " mov r15, r1 \n\t" /* r1 = saved sp */ | 11 | " mova 1f, r0 \n\t" /* r0 = end point */ \ |
12 | " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ | 12 | " mov r15, r1 \n\t" /* r1 = saved sp */ \ |
13 | " mov.l @%1, %0 \n\t" /* load old value */ | 13 | " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ \ |
14 | " add %2, %0 \n\t" /* add */ | 14 | " mov.l @%1, %0 \n\t" /* load old value */ \ |
15 | " mov.l %0, @%1 \n\t" /* store new value */ | 15 | " " #op " %2, %0 \n\t" /* $op */ \ |
16 | "1: mov r1, r15 \n\t" /* LOGOUT */ | 16 | " mov.l %0, @%1 \n\t" /* store new value */ \ |
17 | : "=&r" (tmp), | 17 | "1: mov r1, r15 \n\t" /* LOGOUT */ \ |
18 | "+r" (v) | 18 | : "=&r" (tmp), \ |
19 | : "r" (i) | 19 | "+r" (v) \ |
20 | : "memory" , "r0", "r1"); | 20 | : "r" (i) \ |
21 | } | 21 | : "memory" , "r0", "r1"); \ |
22 | 22 | } \ | |
23 | static inline void atomic_sub(int i, atomic_t *v) | ||
24 | { | ||
25 | int tmp; | ||
26 | |||
27 | __asm__ __volatile__ ( | ||
28 | " .align 2 \n\t" | ||
29 | " mova 1f, r0 \n\t" /* r0 = end point */ | ||
30 | " mov r15, r1 \n\t" /* r1 = saved sp */ | ||
31 | " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ | ||
32 | " mov.l @%1, %0 \n\t" /* load old value */ | ||
33 | " sub %2, %0 \n\t" /* sub */ | ||
34 | " mov.l %0, @%1 \n\t" /* store new value */ | ||
35 | "1: mov r1, r15 \n\t" /* LOGOUT */ | ||
36 | : "=&r" (tmp), | ||
37 | "+r" (v) | ||
38 | : "r" (i) | ||
39 | : "memory" , "r0", "r1"); | ||
40 | } | ||
41 | |||
42 | static inline int atomic_add_return(int i, atomic_t *v) | ||
43 | { | ||
44 | int tmp; | ||
45 | 23 | ||
46 | __asm__ __volatile__ ( | 24 | #define ATOMIC_OP_RETURN(op) \ |
47 | " .align 2 \n\t" | 25 | static inline int atomic_##op##_return(int i, atomic_t *v) \ |
48 | " mova 1f, r0 \n\t" /* r0 = end point */ | 26 | { \ |
49 | " mov r15, r1 \n\t" /* r1 = saved sp */ | 27 | int tmp; \ |
50 | " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ | 28 | \ |
51 | " mov.l @%1, %0 \n\t" /* load old value */ | 29 | __asm__ __volatile__ ( \ |
52 | " add %2, %0 \n\t" /* add */ | 30 | " .align 2 \n\t" \ |
53 | " mov.l %0, @%1 \n\t" /* store new value */ | 31 | " mova 1f, r0 \n\t" /* r0 = end point */ \ |
54 | "1: mov r1, r15 \n\t" /* LOGOUT */ | 32 | " mov r15, r1 \n\t" /* r1 = saved sp */ \ |
55 | : "=&r" (tmp), | 33 | " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ \ |
56 | "+r" (v) | 34 | " mov.l @%1, %0 \n\t" /* load old value */ \ |
57 | : "r" (i) | 35 | " " #op " %2, %0 \n\t" /* $op */ \ |
58 | : "memory" , "r0", "r1"); | 36 | " mov.l %0, @%1 \n\t" /* store new value */ \ |
59 | 37 | "1: mov r1, r15 \n\t" /* LOGOUT */ \ | |
60 | return tmp; | 38 | : "=&r" (tmp), \ |
39 | "+r" (v) \ | ||
40 | : "r" (i) \ | ||
41 | : "memory" , "r0", "r1"); \ | ||
42 | \ | ||
43 | return tmp; \ | ||
61 | } | 44 | } |
62 | 45 | ||
63 | static inline int atomic_sub_return(int i, atomic_t *v) | 46 | #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) |
64 | { | ||
65 | int tmp; | ||
66 | 47 | ||
67 | __asm__ __volatile__ ( | 48 | ATOMIC_OPS(add) |
68 | " .align 2 \n\t" | 49 | ATOMIC_OPS(sub) |
69 | " mova 1f, r0 \n\t" /* r0 = end point */ | ||
70 | " mov r15, r1 \n\t" /* r1 = saved sp */ | ||
71 | " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ | ||
72 | " mov.l @%1, %0 \n\t" /* load old value */ | ||
73 | " sub %2, %0 \n\t" /* sub */ | ||
74 | " mov.l %0, @%1 \n\t" /* store new value */ | ||
75 | "1: mov r1, r15 \n\t" /* LOGOUT */ | ||
76 | : "=&r" (tmp), | ||
77 | "+r" (v) | ||
78 | : "r" (i) | ||
79 | : "memory", "r0", "r1"); | ||
80 | 50 | ||
81 | return tmp; | 51 | #undef ATOMIC_OPS |
82 | } | 52 | #undef ATOMIC_OP_RETURN |
53 | #undef ATOMIC_OP | ||
83 | 54 | ||
84 | static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) | 55 | static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) |
85 | { | 56 | { |
diff --git a/arch/sh/include/asm/atomic-irq.h b/arch/sh/include/asm/atomic-irq.h index 9f7c56609e53..61d107523f06 100644 --- a/arch/sh/include/asm/atomic-irq.h +++ b/arch/sh/include/asm/atomic-irq.h | |||
@@ -8,49 +8,39 @@ | |||
8 | * forward to code at the end of this object's .text section, then | 8 | * forward to code at the end of this object's .text section, then |
9 | * branch back to restart the operation. | 9 | * branch back to restart the operation. |
10 | */ | 10 | */ |
11 | static inline void atomic_add(int i, atomic_t *v) | ||
12 | { | ||
13 | unsigned long flags; | ||
14 | |||
15 | raw_local_irq_save(flags); | ||
16 | v->counter += i; | ||
17 | raw_local_irq_restore(flags); | ||
18 | } | ||
19 | 11 | ||
20 | static inline void atomic_sub(int i, atomic_t *v) | 12 | #define ATOMIC_OP(op, c_op) \ |
21 | { | 13 | static inline void atomic_##op(int i, atomic_t *v) \ |
22 | unsigned long flags; | 14 | { \ |
23 | 15 | unsigned long flags; \ | |
24 | raw_local_irq_save(flags); | 16 | \ |
25 | v->counter -= i; | 17 | raw_local_irq_save(flags); \ |
26 | raw_local_irq_restore(flags); | 18 | v->counter c_op i; \ |
19 | raw_local_irq_restore(flags); \ | ||
27 | } | 20 | } |
28 | 21 | ||
29 | static inline int atomic_add_return(int i, atomic_t *v) | 22 | #define ATOMIC_OP_RETURN(op, c_op) \ |
30 | { | 23 | static inline int atomic_##op##_return(int i, atomic_t *v) \ |
31 | unsigned long temp, flags; | 24 | { \ |
32 | 25 | unsigned long temp, flags; \ | |
33 | raw_local_irq_save(flags); | 26 | \ |
34 | temp = v->counter; | 27 | raw_local_irq_save(flags); \ |
35 | temp += i; | 28 | temp = v->counter; \ |
36 | v->counter = temp; | 29 | temp c_op i; \ |
37 | raw_local_irq_restore(flags); | 30 | v->counter = temp; \ |
38 | 31 | raw_local_irq_restore(flags); \ | |
39 | return temp; | 32 | \ |
33 | return temp; \ | ||
40 | } | 34 | } |
41 | 35 | ||
42 | static inline int atomic_sub_return(int i, atomic_t *v) | 36 | #define ATOMIC_OPS(op, c_op) ATOMIC_OP(op, c_op) ATOMIC_OP_RETURN(op, c_op) |
43 | { | ||
44 | unsigned long temp, flags; | ||
45 | 37 | ||
46 | raw_local_irq_save(flags); | 38 | ATOMIC_OPS(add, +=) |
47 | temp = v->counter; | 39 | ATOMIC_OPS(sub, -=) |
48 | temp -= i; | ||
49 | v->counter = temp; | ||
50 | raw_local_irq_restore(flags); | ||
51 | 40 | ||
52 | return temp; | 41 | #undef ATOMIC_OPS |
53 | } | 42 | #undef ATOMIC_OP_RETURN |
43 | #undef ATOMIC_OP | ||
54 | 44 | ||
55 | static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) | 45 | static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) |
56 | { | 46 | { |
diff --git a/arch/sh/include/asm/atomic-llsc.h b/arch/sh/include/asm/atomic-llsc.h index 4b00b78e3f4f..8575dccb9ef7 100644 --- a/arch/sh/include/asm/atomic-llsc.h +++ b/arch/sh/include/asm/atomic-llsc.h | |||
@@ -2,39 +2,6 @@ | |||
2 | #define __ASM_SH_ATOMIC_LLSC_H | 2 | #define __ASM_SH_ATOMIC_LLSC_H |
3 | 3 | ||
4 | /* | 4 | /* |
5 | * To get proper branch prediction for the main line, we must branch | ||
6 | * forward to code at the end of this object's .text section, then | ||
7 | * branch back to restart the operation. | ||
8 | */ | ||
9 | static inline void atomic_add(int i, atomic_t *v) | ||
10 | { | ||
11 | unsigned long tmp; | ||
12 | |||
13 | __asm__ __volatile__ ( | ||
14 | "1: movli.l @%2, %0 ! atomic_add \n" | ||
15 | " add %1, %0 \n" | ||
16 | " movco.l %0, @%2 \n" | ||
17 | " bf 1b \n" | ||
18 | : "=&z" (tmp) | ||
19 | : "r" (i), "r" (&v->counter) | ||
20 | : "t"); | ||
21 | } | ||
22 | |||
23 | static inline void atomic_sub(int i, atomic_t *v) | ||
24 | { | ||
25 | unsigned long tmp; | ||
26 | |||
27 | __asm__ __volatile__ ( | ||
28 | "1: movli.l @%2, %0 ! atomic_sub \n" | ||
29 | " sub %1, %0 \n" | ||
30 | " movco.l %0, @%2 \n" | ||
31 | " bf 1b \n" | ||
32 | : "=&z" (tmp) | ||
33 | : "r" (i), "r" (&v->counter) | ||
34 | : "t"); | ||
35 | } | ||
36 | |||
37 | /* | ||
38 | * SH-4A note: | 5 | * SH-4A note: |
39 | * | 6 | * |
40 | * We basically get atomic_xxx_return() for free compared with | 7 | * We basically get atomic_xxx_return() for free compared with |
@@ -42,39 +9,53 @@ static inline void atomic_sub(int i, atomic_t *v) | |||
42 | * encoding, so the retval is automatically set without having to | 9 | * encoding, so the retval is automatically set without having to |
43 | * do any special work. | 10 | * do any special work. |
44 | */ | 11 | */ |
45 | static inline int atomic_add_return(int i, atomic_t *v) | 12 | /* |
46 | { | 13 | * To get proper branch prediction for the main line, we must branch |
47 | unsigned long temp; | 14 | * forward to code at the end of this object's .text section, then |
15 | * branch back to restart the operation. | ||
16 | */ | ||
48 | 17 | ||
49 | __asm__ __volatile__ ( | 18 | #define ATOMIC_OP(op) \ |
50 | "1: movli.l @%2, %0 ! atomic_add_return \n" | 19 | static inline void atomic_##op(int i, atomic_t *v) \ |
51 | " add %1, %0 \n" | 20 | { \ |
52 | " movco.l %0, @%2 \n" | 21 | unsigned long tmp; \ |
53 | " bf 1b \n" | 22 | \ |
54 | " synco \n" | 23 | __asm__ __volatile__ ( \ |
55 | : "=&z" (temp) | 24 | "1: movli.l @%2, %0 ! atomic_" #op "\n" \ |
56 | : "r" (i), "r" (&v->counter) | 25 | " " #op " %1, %0 \n" \ |
57 | : "t"); | 26 | " movco.l %0, @%2 \n" \ |
27 | " bf 1b \n" \ | ||
28 | : "=&z" (tmp) \ | ||
29 | : "r" (i), "r" (&v->counter) \ | ||
30 | : "t"); \ | ||
31 | } | ||
58 | 32 | ||
59 | return temp; | 33 | #define ATOMIC_OP_RETURN(op) \ |
34 | static inline int atomic_##op##_return(int i, atomic_t *v) \ | ||
35 | { \ | ||
36 | unsigned long temp; \ | ||
37 | \ | ||
38 | __asm__ __volatile__ ( \ | ||
39 | "1: movli.l @%2, %0 ! atomic_" #op "_return \n" \ | ||
40 | " " #op " %1, %0 \n" \ | ||
41 | " movco.l %0, @%2 \n" \ | ||
42 | " bf 1b \n" \ | ||
43 | " synco \n" \ | ||
44 | : "=&z" (temp) \ | ||
45 | : "r" (i), "r" (&v->counter) \ | ||
46 | : "t"); \ | ||
47 | \ | ||
48 | return temp; \ | ||
60 | } | 49 | } |
61 | 50 | ||
62 | static inline int atomic_sub_return(int i, atomic_t *v) | 51 | #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) |
63 | { | ||
64 | unsigned long temp; | ||
65 | 52 | ||
66 | __asm__ __volatile__ ( | 53 | ATOMIC_OPS(add) |
67 | "1: movli.l @%2, %0 ! atomic_sub_return \n" | 54 | ATOMIC_OPS(sub) |
68 | " sub %1, %0 \n" | ||
69 | " movco.l %0, @%2 \n" | ||
70 | " bf 1b \n" | ||
71 | " synco \n" | ||
72 | : "=&z" (temp) | ||
73 | : "r" (i), "r" (&v->counter) | ||
74 | : "t"); | ||
75 | 55 | ||
76 | return temp; | 56 | #undef ATOMIC_OPS |
77 | } | 57 | #undef ATOMIC_OP_RETURN |
58 | #undef ATOMIC_OP | ||
78 | 59 | ||
79 | static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) | 60 | static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) |
80 | { | 61 | { |
diff --git a/arch/sh/include/asm/atomic.h b/arch/sh/include/asm/atomic.h index f57b8a6743b3..05b9f74ce2d5 100644 --- a/arch/sh/include/asm/atomic.h +++ b/arch/sh/include/asm/atomic.h | |||
@@ -14,7 +14,7 @@ | |||
14 | 14 | ||
15 | #define ATOMIC_INIT(i) { (i) } | 15 | #define ATOMIC_INIT(i) { (i) } |
16 | 16 | ||
17 | #define atomic_read(v) (*(volatile int *)&(v)->counter) | 17 | #define atomic_read(v) ACCESS_ONCE((v)->counter) |
18 | #define atomic_set(v,i) ((v)->counter = (i)) | 18 | #define atomic_set(v,i) ((v)->counter = (i)) |
19 | 19 | ||
20 | #if defined(CONFIG_GUSA_RB) | 20 | #if defined(CONFIG_GUSA_RB) |
diff --git a/arch/sparc/include/asm/atomic_32.h b/arch/sparc/include/asm/atomic_32.h index 7aed2be45b44..765c1776ec9f 100644 --- a/arch/sparc/include/asm/atomic_32.h +++ b/arch/sparc/include/asm/atomic_32.h | |||
@@ -20,23 +20,22 @@ | |||
20 | 20 | ||
21 | #define ATOMIC_INIT(i) { (i) } | 21 | #define ATOMIC_INIT(i) { (i) } |
22 | 22 | ||
23 | int __atomic_add_return(int, atomic_t *); | 23 | int atomic_add_return(int, atomic_t *); |
24 | int atomic_cmpxchg(atomic_t *, int, int); | 24 | int atomic_cmpxchg(atomic_t *, int, int); |
25 | #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) | 25 | #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) |
26 | int __atomic_add_unless(atomic_t *, int, int); | 26 | int __atomic_add_unless(atomic_t *, int, int); |
27 | void atomic_set(atomic_t *, int); | 27 | void atomic_set(atomic_t *, int); |
28 | 28 | ||
29 | #define atomic_read(v) (*(volatile int *)&(v)->counter) | 29 | #define atomic_read(v) ACCESS_ONCE((v)->counter) |
30 | 30 | ||
31 | #define atomic_add(i, v) ((void)__atomic_add_return( (int)(i), (v))) | 31 | #define atomic_add(i, v) ((void)atomic_add_return( (int)(i), (v))) |
32 | #define atomic_sub(i, v) ((void)__atomic_add_return(-(int)(i), (v))) | 32 | #define atomic_sub(i, v) ((void)atomic_add_return(-(int)(i), (v))) |
33 | #define atomic_inc(v) ((void)__atomic_add_return( 1, (v))) | 33 | #define atomic_inc(v) ((void)atomic_add_return( 1, (v))) |
34 | #define atomic_dec(v) ((void)__atomic_add_return( -1, (v))) | 34 | #define atomic_dec(v) ((void)atomic_add_return( -1, (v))) |
35 | 35 | ||
36 | #define atomic_add_return(i, v) (__atomic_add_return( (int)(i), (v))) | 36 | #define atomic_sub_return(i, v) (atomic_add_return(-(int)(i), (v))) |
37 | #define atomic_sub_return(i, v) (__atomic_add_return(-(int)(i), (v))) | 37 | #define atomic_inc_return(v) (atomic_add_return( 1, (v))) |
38 | #define atomic_inc_return(v) (__atomic_add_return( 1, (v))) | 38 | #define atomic_dec_return(v) (atomic_add_return( -1, (v))) |
39 | #define atomic_dec_return(v) (__atomic_add_return( -1, (v))) | ||
40 | 39 | ||
41 | #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) | 40 | #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) |
42 | 41 | ||
diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h index bb894c8bec56..4082749913ce 100644 --- a/arch/sparc/include/asm/atomic_64.h +++ b/arch/sparc/include/asm/atomic_64.h | |||
@@ -14,33 +14,34 @@ | |||
14 | #define ATOMIC_INIT(i) { (i) } | 14 | #define ATOMIC_INIT(i) { (i) } |
15 | #define ATOMIC64_INIT(i) { (i) } | 15 | #define ATOMIC64_INIT(i) { (i) } |
16 | 16 | ||
17 | #define atomic_read(v) (*(volatile int *)&(v)->counter) | 17 | #define atomic_read(v) ACCESS_ONCE((v)->counter) |
18 | #define atomic64_read(v) (*(volatile long *)&(v)->counter) | 18 | #define atomic64_read(v) ACCESS_ONCE((v)->counter) |
19 | 19 | ||
20 | #define atomic_set(v, i) (((v)->counter) = i) | 20 | #define atomic_set(v, i) (((v)->counter) = i) |
21 | #define atomic64_set(v, i) (((v)->counter) = i) | 21 | #define atomic64_set(v, i) (((v)->counter) = i) |
22 | 22 | ||
23 | void atomic_add(int, atomic_t *); | 23 | #define ATOMIC_OP(op) \ |
24 | void atomic64_add(long, atomic64_t *); | 24 | void atomic_##op(int, atomic_t *); \ |
25 | void atomic_sub(int, atomic_t *); | 25 | void atomic64_##op(long, atomic64_t *); |
26 | void atomic64_sub(long, atomic64_t *); | ||
27 | 26 | ||
28 | int atomic_add_ret(int, atomic_t *); | 27 | #define ATOMIC_OP_RETURN(op) \ |
29 | long atomic64_add_ret(long, atomic64_t *); | 28 | int atomic_##op##_return(int, atomic_t *); \ |
30 | int atomic_sub_ret(int, atomic_t *); | 29 | long atomic64_##op##_return(long, atomic64_t *); |
31 | long atomic64_sub_ret(long, atomic64_t *); | ||
32 | 30 | ||
33 | #define atomic_dec_return(v) atomic_sub_ret(1, v) | 31 | #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) |
34 | #define atomic64_dec_return(v) atomic64_sub_ret(1, v) | ||
35 | 32 | ||
36 | #define atomic_inc_return(v) atomic_add_ret(1, v) | 33 | ATOMIC_OPS(add) |
37 | #define atomic64_inc_return(v) atomic64_add_ret(1, v) | 34 | ATOMIC_OPS(sub) |
38 | 35 | ||
39 | #define atomic_sub_return(i, v) atomic_sub_ret(i, v) | 36 | #undef ATOMIC_OPS |
40 | #define atomic64_sub_return(i, v) atomic64_sub_ret(i, v) | 37 | #undef ATOMIC_OP_RETURN |
38 | #undef ATOMIC_OP | ||
41 | 39 | ||
42 | #define atomic_add_return(i, v) atomic_add_ret(i, v) | 40 | #define atomic_dec_return(v) atomic_sub_return(1, v) |
43 | #define atomic64_add_return(i, v) atomic64_add_ret(i, v) | 41 | #define atomic64_dec_return(v) atomic64_sub_return(1, v) |
42 | |||
43 | #define atomic_inc_return(v) atomic_add_return(1, v) | ||
44 | #define atomic64_inc_return(v) atomic64_add_return(1, v) | ||
44 | 45 | ||
45 | /* | 46 | /* |
46 | * atomic_inc_and_test - increment and test | 47 | * atomic_inc_and_test - increment and test |
@@ -53,11 +54,11 @@ long atomic64_sub_ret(long, atomic64_t *); | |||
53 | #define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) | 54 | #define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) |
54 | #define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0) | 55 | #define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0) |
55 | 56 | ||
56 | #define atomic_sub_and_test(i, v) (atomic_sub_ret(i, v) == 0) | 57 | #define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0) |
57 | #define atomic64_sub_and_test(i, v) (atomic64_sub_ret(i, v) == 0) | 58 | #define atomic64_sub_and_test(i, v) (atomic64_sub_return(i, v) == 0) |
58 | 59 | ||
59 | #define atomic_dec_and_test(v) (atomic_sub_ret(1, v) == 0) | 60 | #define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0) |
60 | #define atomic64_dec_and_test(v) (atomic64_sub_ret(1, v) == 0) | 61 | #define atomic64_dec_and_test(v) (atomic64_sub_return(1, v) == 0) |
61 | 62 | ||
62 | #define atomic_inc(v) atomic_add(1, v) | 63 | #define atomic_inc(v) atomic_add(1, v) |
63 | #define atomic64_inc(v) atomic64_add(1, v) | 64 | #define atomic64_inc(v) atomic64_add(1, v) |
@@ -65,8 +66,8 @@ long atomic64_sub_ret(long, atomic64_t *); | |||
65 | #define atomic_dec(v) atomic_sub(1, v) | 66 | #define atomic_dec(v) atomic_sub(1, v) |
66 | #define atomic64_dec(v) atomic64_sub(1, v) | 67 | #define atomic64_dec(v) atomic64_sub(1, v) |
67 | 68 | ||
68 | #define atomic_add_negative(i, v) (atomic_add_ret(i, v) < 0) | 69 | #define atomic_add_negative(i, v) (atomic_add_return(i, v) < 0) |
69 | #define atomic64_add_negative(i, v) (atomic64_add_ret(i, v) < 0) | 70 | #define atomic64_add_negative(i, v) (atomic64_add_return(i, v) < 0) |
70 | 71 | ||
71 | #define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n))) | 72 | #define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n))) |
72 | #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) | 73 | #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) |
diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index c9300bfaee5a..302c476413d5 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c | |||
@@ -1138,7 +1138,7 @@ static unsigned long penguins_are_doing_time; | |||
1138 | 1138 | ||
1139 | void smp_capture(void) | 1139 | void smp_capture(void) |
1140 | { | 1140 | { |
1141 | int result = atomic_add_ret(1, &smp_capture_depth); | 1141 | int result = atomic_add_return(1, &smp_capture_depth); |
1142 | 1142 | ||
1143 | if (result == 1) { | 1143 | if (result == 1) { |
1144 | int ncpus = num_online_cpus(); | 1144 | int ncpus = num_online_cpus(); |
diff --git a/arch/sparc/lib/atomic32.c b/arch/sparc/lib/atomic32.c index 1d32b54089aa..a7c418ac26af 100644 --- a/arch/sparc/lib/atomic32.c +++ b/arch/sparc/lib/atomic32.c | |||
@@ -27,18 +27,23 @@ static DEFINE_SPINLOCK(dummy); | |||
27 | 27 | ||
28 | #endif /* SMP */ | 28 | #endif /* SMP */ |
29 | 29 | ||
30 | int __atomic_add_return(int i, atomic_t *v) | 30 | #define ATOMIC_OP(op, cop) \ |
31 | { | 31 | int atomic_##op##_return(int i, atomic_t *v) \ |
32 | int ret; | 32 | { \ |
33 | unsigned long flags; | 33 | int ret; \ |
34 | spin_lock_irqsave(ATOMIC_HASH(v), flags); | 34 | unsigned long flags; \ |
35 | 35 | spin_lock_irqsave(ATOMIC_HASH(v), flags); \ | |
36 | ret = (v->counter += i); | 36 | \ |
37 | 37 | ret = (v->counter cop i); \ | |
38 | spin_unlock_irqrestore(ATOMIC_HASH(v), flags); | 38 | \ |
39 | return ret; | 39 | spin_unlock_irqrestore(ATOMIC_HASH(v), flags); \ |
40 | } | 40 | return ret; \ |
41 | EXPORT_SYMBOL(__atomic_add_return); | 41 | } \ |
42 | EXPORT_SYMBOL(atomic_##op##_return); | ||
43 | |||
44 | ATOMIC_OP(add, +=) | ||
45 | |||
46 | #undef ATOMIC_OP | ||
42 | 47 | ||
43 | int atomic_cmpxchg(atomic_t *v, int old, int new) | 48 | int atomic_cmpxchg(atomic_t *v, int old, int new) |
44 | { | 49 | { |
diff --git a/arch/sparc/lib/atomic_64.S b/arch/sparc/lib/atomic_64.S index 85c233d0a340..05dac43907d1 100644 --- a/arch/sparc/lib/atomic_64.S +++ b/arch/sparc/lib/atomic_64.S | |||
@@ -14,109 +14,80 @@ | |||
14 | * memory barriers, and a second which returns | 14 | * memory barriers, and a second which returns |
15 | * a value and does the barriers. | 15 | * a value and does the barriers. |
16 | */ | 16 | */ |
17 | ENTRY(atomic_add) /* %o0 = increment, %o1 = atomic_ptr */ | ||
18 | BACKOFF_SETUP(%o2) | ||
19 | 1: lduw [%o1], %g1 | ||
20 | add %g1, %o0, %g7 | ||
21 | cas [%o1], %g1, %g7 | ||
22 | cmp %g1, %g7 | ||
23 | bne,pn %icc, BACKOFF_LABEL(2f, 1b) | ||
24 | nop | ||
25 | retl | ||
26 | nop | ||
27 | 2: BACKOFF_SPIN(%o2, %o3, 1b) | ||
28 | ENDPROC(atomic_add) | ||
29 | 17 | ||
30 | ENTRY(atomic_sub) /* %o0 = decrement, %o1 = atomic_ptr */ | 18 | #define ATOMIC_OP(op) \ |
31 | BACKOFF_SETUP(%o2) | 19 | ENTRY(atomic_##op) /* %o0 = increment, %o1 = atomic_ptr */ \ |
32 | 1: lduw [%o1], %g1 | 20 | BACKOFF_SETUP(%o2); \ |
33 | sub %g1, %o0, %g7 | 21 | 1: lduw [%o1], %g1; \ |
34 | cas [%o1], %g1, %g7 | 22 | op %g1, %o0, %g7; \ |
35 | cmp %g1, %g7 | 23 | cas [%o1], %g1, %g7; \ |
36 | bne,pn %icc, BACKOFF_LABEL(2f, 1b) | 24 | cmp %g1, %g7; \ |
37 | nop | 25 | bne,pn %icc, BACKOFF_LABEL(2f, 1b); \ |
38 | retl | 26 | nop; \ |
39 | nop | 27 | retl; \ |
40 | 2: BACKOFF_SPIN(%o2, %o3, 1b) | 28 | nop; \ |
41 | ENDPROC(atomic_sub) | 29 | 2: BACKOFF_SPIN(%o2, %o3, 1b); \ |
30 | ENDPROC(atomic_##op); \ | ||
42 | 31 | ||
43 | ENTRY(atomic_add_ret) /* %o0 = increment, %o1 = atomic_ptr */ | 32 | #define ATOMIC_OP_RETURN(op) \ |
44 | BACKOFF_SETUP(%o2) | 33 | ENTRY(atomic_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */ \ |
45 | 1: lduw [%o1], %g1 | 34 | BACKOFF_SETUP(%o2); \ |
46 | add %g1, %o0, %g7 | 35 | 1: lduw [%o1], %g1; \ |
47 | cas [%o1], %g1, %g7 | 36 | op %g1, %o0, %g7; \ |
48 | cmp %g1, %g7 | 37 | cas [%o1], %g1, %g7; \ |
49 | bne,pn %icc, BACKOFF_LABEL(2f, 1b) | 38 | cmp %g1, %g7; \ |
50 | add %g1, %o0, %g1 | 39 | bne,pn %icc, BACKOFF_LABEL(2f, 1b); \ |
51 | retl | 40 | op %g1, %o0, %g1; \ |
52 | sra %g1, 0, %o0 | 41 | retl; \ |
53 | 2: BACKOFF_SPIN(%o2, %o3, 1b) | 42 | sra %g1, 0, %o0; \ |
54 | ENDPROC(atomic_add_ret) | 43 | 2: BACKOFF_SPIN(%o2, %o3, 1b); \ |
44 | ENDPROC(atomic_##op##_return); | ||
55 | 45 | ||
56 | ENTRY(atomic_sub_ret) /* %o0 = decrement, %o1 = atomic_ptr */ | 46 | #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) |
57 | BACKOFF_SETUP(%o2) | ||
58 | 1: lduw [%o1], %g1 | ||
59 | sub %g1, %o0, %g7 | ||
60 | cas [%o1], %g1, %g7 | ||
61 | cmp %g1, %g7 | ||
62 | bne,pn %icc, BACKOFF_LABEL(2f, 1b) | ||
63 | sub %g1, %o0, %g1 | ||
64 | retl | ||
65 | sra %g1, 0, %o0 | ||
66 | 2: BACKOFF_SPIN(%o2, %o3, 1b) | ||
67 | ENDPROC(atomic_sub_ret) | ||
68 | 47 | ||
69 | ENTRY(atomic64_add) /* %o0 = increment, %o1 = atomic_ptr */ | 48 | ATOMIC_OPS(add) |
70 | BACKOFF_SETUP(%o2) | 49 | ATOMIC_OPS(sub) |
71 | 1: ldx [%o1], %g1 | ||
72 | add %g1, %o0, %g7 | ||
73 | casx [%o1], %g1, %g7 | ||
74 | cmp %g1, %g7 | ||
75 | bne,pn %xcc, BACKOFF_LABEL(2f, 1b) | ||
76 | nop | ||
77 | retl | ||
78 | nop | ||
79 | 2: BACKOFF_SPIN(%o2, %o3, 1b) | ||
80 | ENDPROC(atomic64_add) | ||
81 | 50 | ||
82 | ENTRY(atomic64_sub) /* %o0 = decrement, %o1 = atomic_ptr */ | 51 | #undef ATOMIC_OPS |
83 | BACKOFF_SETUP(%o2) | 52 | #undef ATOMIC_OP_RETURN |
84 | 1: ldx [%o1], %g1 | 53 | #undef ATOMIC_OP |
85 | sub %g1, %o0, %g7 | ||
86 | casx [%o1], %g1, %g7 | ||
87 | cmp %g1, %g7 | ||
88 | bne,pn %xcc, BACKOFF_LABEL(2f, 1b) | ||
89 | nop | ||
90 | retl | ||
91 | nop | ||
92 | 2: BACKOFF_SPIN(%o2, %o3, 1b) | ||
93 | ENDPROC(atomic64_sub) | ||
94 | 54 | ||
95 | ENTRY(atomic64_add_ret) /* %o0 = increment, %o1 = atomic_ptr */ | 55 | #define ATOMIC64_OP(op) \ |
96 | BACKOFF_SETUP(%o2) | 56 | ENTRY(atomic64_##op) /* %o0 = increment, %o1 = atomic_ptr */ \ |
97 | 1: ldx [%o1], %g1 | 57 | BACKOFF_SETUP(%o2); \ |
98 | add %g1, %o0, %g7 | 58 | 1: ldx [%o1], %g1; \ |
99 | casx [%o1], %g1, %g7 | 59 | op %g1, %o0, %g7; \ |
100 | cmp %g1, %g7 | 60 | casx [%o1], %g1, %g7; \ |
101 | bne,pn %xcc, BACKOFF_LABEL(2f, 1b) | 61 | cmp %g1, %g7; \ |
102 | nop | 62 | bne,pn %xcc, BACKOFF_LABEL(2f, 1b); \ |
103 | retl | 63 | nop; \ |
104 | add %g1, %o0, %o0 | 64 | retl; \ |
105 | 2: BACKOFF_SPIN(%o2, %o3, 1b) | 65 | nop; \ |
106 | ENDPROC(atomic64_add_ret) | 66 | 2: BACKOFF_SPIN(%o2, %o3, 1b); \ |
67 | ENDPROC(atomic64_##op); \ | ||
107 | 68 | ||
108 | ENTRY(atomic64_sub_ret) /* %o0 = decrement, %o1 = atomic_ptr */ | 69 | #define ATOMIC64_OP_RETURN(op) \ |
109 | BACKOFF_SETUP(%o2) | 70 | ENTRY(atomic64_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */ \ |
110 | 1: ldx [%o1], %g1 | 71 | BACKOFF_SETUP(%o2); \ |
111 | sub %g1, %o0, %g7 | 72 | 1: ldx [%o1], %g1; \ |
112 | casx [%o1], %g1, %g7 | 73 | op %g1, %o0, %g7; \ |
113 | cmp %g1, %g7 | 74 | casx [%o1], %g1, %g7; \ |
114 | bne,pn %xcc, BACKOFF_LABEL(2f, 1b) | 75 | cmp %g1, %g7; \ |
115 | nop | 76 | bne,pn %xcc, BACKOFF_LABEL(2f, 1b); \ |
116 | retl | 77 | nop; \ |
117 | sub %g1, %o0, %o0 | 78 | retl; \ |
118 | 2: BACKOFF_SPIN(%o2, %o3, 1b) | 79 | op %g1, %o0, %o0; \ |
119 | ENDPROC(atomic64_sub_ret) | 80 | 2: BACKOFF_SPIN(%o2, %o3, 1b); \ |
81 | ENDPROC(atomic64_##op##_return); | ||
82 | |||
83 | #define ATOMIC64_OPS(op) ATOMIC64_OP(op) ATOMIC64_OP_RETURN(op) | ||
84 | |||
85 | ATOMIC64_OPS(add) | ||
86 | ATOMIC64_OPS(sub) | ||
87 | |||
88 | #undef ATOMIC64_OPS | ||
89 | #undef ATOMIC64_OP_RETURN | ||
90 | #undef ATOMIC64_OP | ||
120 | 91 | ||
121 | ENTRY(atomic64_dec_if_positive) /* %o0 = atomic_ptr */ | 92 | ENTRY(atomic64_dec_if_positive) /* %o0 = atomic_ptr */ |
122 | BACKOFF_SETUP(%o2) | 93 | BACKOFF_SETUP(%o2) |
diff --git a/arch/sparc/lib/ksyms.c b/arch/sparc/lib/ksyms.c index 323335b9cd2b..1d649a95660c 100644 --- a/arch/sparc/lib/ksyms.c +++ b/arch/sparc/lib/ksyms.c | |||
@@ -99,14 +99,23 @@ EXPORT_SYMBOL(___copy_in_user); | |||
99 | EXPORT_SYMBOL(__clear_user); | 99 | EXPORT_SYMBOL(__clear_user); |
100 | 100 | ||
101 | /* Atomic counter implementation. */ | 101 | /* Atomic counter implementation. */ |
102 | EXPORT_SYMBOL(atomic_add); | 102 | #define ATOMIC_OP(op) \ |
103 | EXPORT_SYMBOL(atomic_add_ret); | 103 | EXPORT_SYMBOL(atomic_##op); \ |
104 | EXPORT_SYMBOL(atomic_sub); | 104 | EXPORT_SYMBOL(atomic64_##op); |
105 | EXPORT_SYMBOL(atomic_sub_ret); | 105 | |
106 | EXPORT_SYMBOL(atomic64_add); | 106 | #define ATOMIC_OP_RETURN(op) \ |
107 | EXPORT_SYMBOL(atomic64_add_ret); | 107 | EXPORT_SYMBOL(atomic_##op##_return); \ |
108 | EXPORT_SYMBOL(atomic64_sub); | 108 | EXPORT_SYMBOL(atomic64_##op##_return); |
109 | EXPORT_SYMBOL(atomic64_sub_ret); | 109 | |
110 | #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) | ||
111 | |||
112 | ATOMIC_OPS(add) | ||
113 | ATOMIC_OPS(sub) | ||
114 | |||
115 | #undef ATOMIC_OPS | ||
116 | #undef ATOMIC_OP_RETURN | ||
117 | #undef ATOMIC_OP | ||
118 | |||
110 | EXPORT_SYMBOL(atomic64_dec_if_positive); | 119 | EXPORT_SYMBOL(atomic64_dec_if_positive); |
111 | 120 | ||
112 | /* Atomic bit operations. */ | 121 | /* Atomic bit operations. */ |
diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h index 6dd1c7dd0473..5e5cd123fdfb 100644 --- a/arch/x86/include/asm/atomic.h +++ b/arch/x86/include/asm/atomic.h | |||
@@ -24,7 +24,7 @@ | |||
24 | */ | 24 | */ |
25 | static inline int atomic_read(const atomic_t *v) | 25 | static inline int atomic_read(const atomic_t *v) |
26 | { | 26 | { |
27 | return (*(volatile int *)&(v)->counter); | 27 | return ACCESS_ONCE((v)->counter); |
28 | } | 28 | } |
29 | 29 | ||
30 | /** | 30 | /** |
@@ -219,21 +219,6 @@ static inline short int atomic_inc_short(short int *v) | |||
219 | return *v; | 219 | return *v; |
220 | } | 220 | } |
221 | 221 | ||
222 | #ifdef CONFIG_X86_64 | ||
223 | /** | ||
224 | * atomic_or_long - OR of two long integers | ||
225 | * @v1: pointer to type unsigned long | ||
226 | * @v2: pointer to type unsigned long | ||
227 | * | ||
228 | * Atomically ORs @v1 and @v2 | ||
229 | * Returns the result of the OR | ||
230 | */ | ||
231 | static inline void atomic_or_long(unsigned long *v1, unsigned long v2) | ||
232 | { | ||
233 | asm(LOCK_PREFIX "orq %1, %0" : "+m" (*v1) : "r" (v2)); | ||
234 | } | ||
235 | #endif | ||
236 | |||
237 | /* These are x86-specific, used by some header files */ | 222 | /* These are x86-specific, used by some header files */ |
238 | #define atomic_clear_mask(mask, addr) \ | 223 | #define atomic_clear_mask(mask, addr) \ |
239 | asm volatile(LOCK_PREFIX "andl %0,%1" \ | 224 | asm volatile(LOCK_PREFIX "andl %0,%1" \ |
diff --git a/arch/x86/include/asm/atomic64_64.h b/arch/x86/include/asm/atomic64_64.h index 46e9052bbd28..f8d273e18516 100644 --- a/arch/x86/include/asm/atomic64_64.h +++ b/arch/x86/include/asm/atomic64_64.h | |||
@@ -18,7 +18,7 @@ | |||
18 | */ | 18 | */ |
19 | static inline long atomic64_read(const atomic64_t *v) | 19 | static inline long atomic64_read(const atomic64_t *v) |
20 | { | 20 | { |
21 | return (*(volatile long *)&(v)->counter); | 21 | return ACCESS_ONCE((v)->counter); |
22 | } | 22 | } |
23 | 23 | ||
24 | /** | 24 | /** |
diff --git a/arch/xtensa/include/asm/atomic.h b/arch/xtensa/include/asm/atomic.h index e5103b47a8ce..00b7d46b35b8 100644 --- a/arch/xtensa/include/asm/atomic.h +++ b/arch/xtensa/include/asm/atomic.h | |||
@@ -47,7 +47,7 @@ | |||
47 | * | 47 | * |
48 | * Atomically reads the value of @v. | 48 | * Atomically reads the value of @v. |
49 | */ | 49 | */ |
50 | #define atomic_read(v) (*(volatile int *)&(v)->counter) | 50 | #define atomic_read(v) ACCESS_ONCE((v)->counter) |
51 | 51 | ||
52 | /** | 52 | /** |
53 | * atomic_set - set atomic variable | 53 | * atomic_set - set atomic variable |
@@ -58,165 +58,96 @@ | |||
58 | */ | 58 | */ |
59 | #define atomic_set(v,i) ((v)->counter = (i)) | 59 | #define atomic_set(v,i) ((v)->counter = (i)) |
60 | 60 | ||
61 | /** | ||
62 | * atomic_add - add integer to atomic variable | ||
63 | * @i: integer value to add | ||
64 | * @v: pointer of type atomic_t | ||
65 | * | ||
66 | * Atomically adds @i to @v. | ||
67 | */ | ||
68 | static inline void atomic_add(int i, atomic_t * v) | ||
69 | { | ||
70 | #if XCHAL_HAVE_S32C1I | 61 | #if XCHAL_HAVE_S32C1I |
71 | unsigned long tmp; | 62 | #define ATOMIC_OP(op) \ |
72 | int result; | 63 | static inline void atomic_##op(int i, atomic_t * v) \ |
73 | 64 | { \ | |
74 | __asm__ __volatile__( | 65 | unsigned long tmp; \ |
75 | "1: l32i %1, %3, 0\n" | 66 | int result; \ |
76 | " wsr %1, scompare1\n" | 67 | \ |
77 | " add %0, %1, %2\n" | 68 | __asm__ __volatile__( \ |
78 | " s32c1i %0, %3, 0\n" | 69 | "1: l32i %1, %3, 0\n" \ |
79 | " bne %0, %1, 1b\n" | 70 | " wsr %1, scompare1\n" \ |
80 | : "=&a" (result), "=&a" (tmp) | 71 | " " #op " %0, %1, %2\n" \ |
81 | : "a" (i), "a" (v) | 72 | " s32c1i %0, %3, 0\n" \ |
82 | : "memory" | 73 | " bne %0, %1, 1b\n" \ |
83 | ); | 74 | : "=&a" (result), "=&a" (tmp) \ |
84 | #else | 75 | : "a" (i), "a" (v) \ |
85 | unsigned int vval; | 76 | : "memory" \ |
86 | 77 | ); \ | |
87 | __asm__ __volatile__( | 78 | } \ |
88 | " rsil a15, "__stringify(LOCKLEVEL)"\n" | 79 | |
89 | " l32i %0, %2, 0\n" | 80 | #define ATOMIC_OP_RETURN(op) \ |
90 | " add %0, %0, %1\n" | 81 | static inline int atomic_##op##_return(int i, atomic_t * v) \ |
91 | " s32i %0, %2, 0\n" | 82 | { \ |
92 | " wsr a15, ps\n" | 83 | unsigned long tmp; \ |
93 | " rsync\n" | 84 | int result; \ |
94 | : "=&a" (vval) | 85 | \ |
95 | : "a" (i), "a" (v) | 86 | __asm__ __volatile__( \ |
96 | : "a15", "memory" | 87 | "1: l32i %1, %3, 0\n" \ |
97 | ); | 88 | " wsr %1, scompare1\n" \ |
98 | #endif | 89 | " " #op " %0, %1, %2\n" \ |
99 | } | 90 | " s32c1i %0, %3, 0\n" \ |
100 | 91 | " bne %0, %1, 1b\n" \ | |
101 | /** | 92 | " " #op " %0, %0, %2\n" \ |
102 | * atomic_sub - subtract the atomic variable | 93 | : "=&a" (result), "=&a" (tmp) \ |
103 | * @i: integer value to subtract | 94 | : "a" (i), "a" (v) \ |
104 | * @v: pointer of type atomic_t | 95 | : "memory" \ |
105 | * | 96 | ); \ |
106 | * Atomically subtracts @i from @v. | 97 | \ |
107 | */ | 98 | return result; \ |
108 | static inline void atomic_sub(int i, atomic_t *v) | ||
109 | { | ||
110 | #if XCHAL_HAVE_S32C1I | ||
111 | unsigned long tmp; | ||
112 | int result; | ||
113 | |||
114 | __asm__ __volatile__( | ||
115 | "1: l32i %1, %3, 0\n" | ||
116 | " wsr %1, scompare1\n" | ||
117 | " sub %0, %1, %2\n" | ||
118 | " s32c1i %0, %3, 0\n" | ||
119 | " bne %0, %1, 1b\n" | ||
120 | : "=&a" (result), "=&a" (tmp) | ||
121 | : "a" (i), "a" (v) | ||
122 | : "memory" | ||
123 | ); | ||
124 | #else | ||
125 | unsigned int vval; | ||
126 | |||
127 | __asm__ __volatile__( | ||
128 | " rsil a15, "__stringify(LOCKLEVEL)"\n" | ||
129 | " l32i %0, %2, 0\n" | ||
130 | " sub %0, %0, %1\n" | ||
131 | " s32i %0, %2, 0\n" | ||
132 | " wsr a15, ps\n" | ||
133 | " rsync\n" | ||
134 | : "=&a" (vval) | ||
135 | : "a" (i), "a" (v) | ||
136 | : "a15", "memory" | ||
137 | ); | ||
138 | #endif | ||
139 | } | 99 | } |
140 | 100 | ||
141 | /* | 101 | #else /* XCHAL_HAVE_S32C1I */ |
142 | * We use atomic_{add|sub}_return to define other functions. | 102 | |
143 | */ | 103 | #define ATOMIC_OP(op) \ |
144 | 104 | static inline void atomic_##op(int i, atomic_t * v) \ | |
145 | static inline int atomic_add_return(int i, atomic_t * v) | 105 | { \ |
146 | { | 106 | unsigned int vval; \ |
147 | #if XCHAL_HAVE_S32C1I | 107 | \ |
148 | unsigned long tmp; | 108 | __asm__ __volatile__( \ |
149 | int result; | 109 | " rsil a15, "__stringify(LOCKLEVEL)"\n"\ |
150 | 110 | " l32i %0, %2, 0\n" \ | |
151 | __asm__ __volatile__( | 111 | " " #op " %0, %0, %1\n" \ |
152 | "1: l32i %1, %3, 0\n" | 112 | " s32i %0, %2, 0\n" \ |
153 | " wsr %1, scompare1\n" | 113 | " wsr a15, ps\n" \ |
154 | " add %0, %1, %2\n" | 114 | " rsync\n" \ |
155 | " s32c1i %0, %3, 0\n" | 115 | : "=&a" (vval) \ |
156 | " bne %0, %1, 1b\n" | 116 | : "a" (i), "a" (v) \ |
157 | " add %0, %0, %2\n" | 117 | : "a15", "memory" \ |
158 | : "=&a" (result), "=&a" (tmp) | 118 | ); \ |
159 | : "a" (i), "a" (v) | 119 | } \ |
160 | : "memory" | 120 | |
161 | ); | 121 | #define ATOMIC_OP_RETURN(op) \ |
162 | 122 | static inline int atomic_##op##_return(int i, atomic_t * v) \ | |
163 | return result; | 123 | { \ |
164 | #else | 124 | unsigned int vval; \ |
165 | unsigned int vval; | 125 | \ |
166 | 126 | __asm__ __volatile__( \ | |
167 | __asm__ __volatile__( | 127 | " rsil a15,"__stringify(LOCKLEVEL)"\n" \ |
168 | " rsil a15,"__stringify(LOCKLEVEL)"\n" | 128 | " l32i %0, %2, 0\n" \ |
169 | " l32i %0, %2, 0\n" | 129 | " " #op " %0, %0, %1\n" \ |
170 | " add %0, %0, %1\n" | 130 | " s32i %0, %2, 0\n" \ |
171 | " s32i %0, %2, 0\n" | 131 | " wsr a15, ps\n" \ |
172 | " wsr a15, ps\n" | 132 | " rsync\n" \ |
173 | " rsync\n" | 133 | : "=&a" (vval) \ |
174 | : "=&a" (vval) | 134 | : "a" (i), "a" (v) \ |
175 | : "a" (i), "a" (v) | 135 | : "a15", "memory" \ |
176 | : "a15", "memory" | 136 | ); \ |
177 | ); | 137 | \ |
178 | 138 | return vval; \ | |
179 | return vval; | ||
180 | #endif | ||
181 | } | 139 | } |
182 | 140 | ||
183 | static inline int atomic_sub_return(int i, atomic_t * v) | 141 | #endif /* XCHAL_HAVE_S32C1I */ |
184 | { | ||
185 | #if XCHAL_HAVE_S32C1I | ||
186 | unsigned long tmp; | ||
187 | int result; | ||
188 | 142 | ||
189 | __asm__ __volatile__( | 143 | #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) |
190 | "1: l32i %1, %3, 0\n" | ||
191 | " wsr %1, scompare1\n" | ||
192 | " sub %0, %1, %2\n" | ||
193 | " s32c1i %0, %3, 0\n" | ||
194 | " bne %0, %1, 1b\n" | ||
195 | " sub %0, %0, %2\n" | ||
196 | : "=&a" (result), "=&a" (tmp) | ||
197 | : "a" (i), "a" (v) | ||
198 | : "memory" | ||
199 | ); | ||
200 | 144 | ||
201 | return result; | 145 | ATOMIC_OPS(add) |
202 | #else | 146 | ATOMIC_OPS(sub) |
203 | unsigned int vval; | ||
204 | |||
205 | __asm__ __volatile__( | ||
206 | " rsil a15,"__stringify(LOCKLEVEL)"\n" | ||
207 | " l32i %0, %2, 0\n" | ||
208 | " sub %0, %0, %1\n" | ||
209 | " s32i %0, %2, 0\n" | ||
210 | " wsr a15, ps\n" | ||
211 | " rsync\n" | ||
212 | : "=&a" (vval) | ||
213 | : "a" (i), "a" (v) | ||
214 | : "a15", "memory" | ||
215 | ); | ||
216 | 147 | ||
217 | return vval; | 148 | #undef ATOMIC_OPS |
218 | #endif | 149 | #undef ATOMIC_OP_RETURN |
219 | } | 150 | #undef ATOMIC_OP |
220 | 151 | ||
221 | /** | 152 | /** |
222 | * atomic_sub_and_test - subtract value from variable and test result | 153 | * atomic_sub_and_test - subtract value from variable and test result |
diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h index 9c79e7603459..1973ad2b13f4 100644 --- a/include/asm-generic/atomic.h +++ b/include/asm-generic/atomic.h | |||
@@ -18,14 +18,100 @@ | |||
18 | #include <asm/cmpxchg.h> | 18 | #include <asm/cmpxchg.h> |
19 | #include <asm/barrier.h> | 19 | #include <asm/barrier.h> |
20 | 20 | ||
21 | /* | ||
22 | * atomic_$op() - $op integer to atomic variable | ||
23 | * @i: integer value to $op | ||
24 | * @v: pointer to the atomic variable | ||
25 | * | ||
26 | * Atomically $ops @i to @v. Does not strictly guarantee a memory-barrier, use | ||
27 | * smp_mb__{before,after}_atomic(). | ||
28 | */ | ||
29 | |||
30 | /* | ||
31 | * atomic_$op_return() - $op interer to atomic variable and returns the result | ||
32 | * @i: integer value to $op | ||
33 | * @v: pointer to the atomic variable | ||
34 | * | ||
35 | * Atomically $ops @i to @v. Does imply a full memory barrier. | ||
36 | */ | ||
37 | |||
21 | #ifdef CONFIG_SMP | 38 | #ifdef CONFIG_SMP |
22 | /* Force people to define core atomics */ | 39 | |
23 | # if !defined(atomic_add_return) || !defined(atomic_sub_return) || \ | 40 | /* we can build all atomic primitives from cmpxchg */ |
24 | !defined(atomic_clear_mask) || !defined(atomic_set_mask) | 41 | |
25 | # error "SMP requires a little arch-specific magic" | 42 | #define ATOMIC_OP(op, c_op) \ |
26 | # endif | 43 | static inline void atomic_##op(int i, atomic_t *v) \ |
44 | { \ | ||
45 | int c, old; \ | ||
46 | \ | ||
47 | c = v->counter; \ | ||
48 | while ((old = cmpxchg(&v->counter, c, c c_op i)) != c) \ | ||
49 | c = old; \ | ||
50 | } | ||
51 | |||
52 | #define ATOMIC_OP_RETURN(op, c_op) \ | ||
53 | static inline int atomic_##op##_return(int i, atomic_t *v) \ | ||
54 | { \ | ||
55 | int c, old; \ | ||
56 | \ | ||
57 | c = v->counter; \ | ||
58 | while ((old = cmpxchg(&v->counter, c, c c_op i)) != c) \ | ||
59 | c = old; \ | ||
60 | \ | ||
61 | return c c_op i; \ | ||
62 | } | ||
63 | |||
64 | #else | ||
65 | |||
66 | #include <linux/irqflags.h> | ||
67 | |||
68 | #define ATOMIC_OP(op, c_op) \ | ||
69 | static inline void atomic_##op(int i, atomic_t *v) \ | ||
70 | { \ | ||
71 | unsigned long flags; \ | ||
72 | \ | ||
73 | raw_local_irq_save(flags); \ | ||
74 | v->counter = v->counter c_op i; \ | ||
75 | raw_local_irq_restore(flags); \ | ||
76 | } | ||
77 | |||
78 | #define ATOMIC_OP_RETURN(op, c_op) \ | ||
79 | static inline int atomic_##op##_return(int i, atomic_t *v) \ | ||
80 | { \ | ||
81 | unsigned long flags; \ | ||
82 | int ret; \ | ||
83 | \ | ||
84 | raw_local_irq_save(flags); \ | ||
85 | ret = (v->counter = v->counter c_op i); \ | ||
86 | raw_local_irq_restore(flags); \ | ||
87 | \ | ||
88 | return ret; \ | ||
89 | } | ||
90 | |||
91 | #endif /* CONFIG_SMP */ | ||
92 | |||
93 | #ifndef atomic_add_return | ||
94 | ATOMIC_OP_RETURN(add, +) | ||
95 | #endif | ||
96 | |||
97 | #ifndef atomic_sub_return | ||
98 | ATOMIC_OP_RETURN(sub, -) | ||
99 | #endif | ||
100 | |||
101 | #ifndef atomic_clear_mask | ||
102 | ATOMIC_OP(and, &) | ||
103 | #define atomic_clear_mask(i, v) atomic_and(~(i), (v)) | ||
27 | #endif | 104 | #endif |
28 | 105 | ||
106 | #ifndef atomic_set_mask | ||
107 | #define CONFIG_ARCH_HAS_ATOMIC_OR | ||
108 | ATOMIC_OP(or, |) | ||
109 | #define atomic_set_mask(i, v) atomic_or((i), (v)) | ||
110 | #endif | ||
111 | |||
112 | #undef ATOMIC_OP_RETURN | ||
113 | #undef ATOMIC_OP | ||
114 | |||
29 | /* | 115 | /* |
30 | * Atomic operations that C can't guarantee us. Useful for | 116 | * Atomic operations that C can't guarantee us. Useful for |
31 | * resource counting etc.. | 117 | * resource counting etc.. |
@@ -33,8 +119,6 @@ | |||
33 | 119 | ||
34 | #define ATOMIC_INIT(i) { (i) } | 120 | #define ATOMIC_INIT(i) { (i) } |
35 | 121 | ||
36 | #ifdef __KERNEL__ | ||
37 | |||
38 | /** | 122 | /** |
39 | * atomic_read - read atomic variable | 123 | * atomic_read - read atomic variable |
40 | * @v: pointer of type atomic_t | 124 | * @v: pointer of type atomic_t |
@@ -42,7 +126,7 @@ | |||
42 | * Atomically reads the value of @v. | 126 | * Atomically reads the value of @v. |
43 | */ | 127 | */ |
44 | #ifndef atomic_read | 128 | #ifndef atomic_read |
45 | #define atomic_read(v) (*(volatile int *)&(v)->counter) | 129 | #define atomic_read(v) ACCESS_ONCE((v)->counter) |
46 | #endif | 130 | #endif |
47 | 131 | ||
48 | /** | 132 | /** |
@@ -56,52 +140,6 @@ | |||
56 | 140 | ||
57 | #include <linux/irqflags.h> | 141 | #include <linux/irqflags.h> |
58 | 142 | ||
59 | /** | ||
60 | * atomic_add_return - add integer to atomic variable | ||
61 | * @i: integer value to add | ||
62 | * @v: pointer of type atomic_t | ||
63 | * | ||
64 | * Atomically adds @i to @v and returns the result | ||
65 | */ | ||
66 | #ifndef atomic_add_return | ||
67 | static inline int atomic_add_return(int i, atomic_t *v) | ||
68 | { | ||
69 | unsigned long flags; | ||
70 | int temp; | ||
71 | |||
72 | raw_local_irq_save(flags); /* Don't trace it in an irqsoff handler */ | ||
73 | temp = v->counter; | ||
74 | temp += i; | ||
75 | v->counter = temp; | ||
76 | raw_local_irq_restore(flags); | ||
77 | |||
78 | return temp; | ||
79 | } | ||
80 | #endif | ||
81 | |||
82 | /** | ||
83 | * atomic_sub_return - subtract integer from atomic variable | ||
84 | * @i: integer value to subtract | ||
85 | * @v: pointer of type atomic_t | ||
86 | * | ||
87 | * Atomically subtracts @i from @v and returns the result | ||
88 | */ | ||
89 | #ifndef atomic_sub_return | ||
90 | static inline int atomic_sub_return(int i, atomic_t *v) | ||
91 | { | ||
92 | unsigned long flags; | ||
93 | int temp; | ||
94 | |||
95 | raw_local_irq_save(flags); /* Don't trace it in an irqsoff handler */ | ||
96 | temp = v->counter; | ||
97 | temp -= i; | ||
98 | v->counter = temp; | ||
99 | raw_local_irq_restore(flags); | ||
100 | |||
101 | return temp; | ||
102 | } | ||
103 | #endif | ||
104 | |||
105 | static inline int atomic_add_negative(int i, atomic_t *v) | 143 | static inline int atomic_add_negative(int i, atomic_t *v) |
106 | { | 144 | { |
107 | return atomic_add_return(i, v) < 0; | 145 | return atomic_add_return(i, v) < 0; |
@@ -139,49 +177,11 @@ static inline void atomic_dec(atomic_t *v) | |||
139 | 177 | ||
140 | static inline int __atomic_add_unless(atomic_t *v, int a, int u) | 178 | static inline int __atomic_add_unless(atomic_t *v, int a, int u) |
141 | { | 179 | { |
142 | int c, old; | 180 | int c, old; |
143 | c = atomic_read(v); | 181 | c = atomic_read(v); |
144 | while (c != u && (old = atomic_cmpxchg(v, c, c + a)) != c) | 182 | while (c != u && (old = atomic_cmpxchg(v, c, c + a)) != c) |
145 | c = old; | 183 | c = old; |
146 | return c; | 184 | return c; |
147 | } | ||
148 | |||
149 | /** | ||
150 | * atomic_clear_mask - Atomically clear bits in atomic variable | ||
151 | * @mask: Mask of the bits to be cleared | ||
152 | * @v: pointer of type atomic_t | ||
153 | * | ||
154 | * Atomically clears the bits set in @mask from @v | ||
155 | */ | ||
156 | #ifndef atomic_clear_mask | ||
157 | static inline void atomic_clear_mask(unsigned long mask, atomic_t *v) | ||
158 | { | ||
159 | unsigned long flags; | ||
160 | |||
161 | mask = ~mask; | ||
162 | raw_local_irq_save(flags); /* Don't trace it in a irqsoff handler */ | ||
163 | v->counter &= mask; | ||
164 | raw_local_irq_restore(flags); | ||
165 | } | 185 | } |
166 | #endif | ||
167 | |||
168 | /** | ||
169 | * atomic_set_mask - Atomically set bits in atomic variable | ||
170 | * @mask: Mask of the bits to be set | ||
171 | * @v: pointer of type atomic_t | ||
172 | * | ||
173 | * Atomically sets the bits set in @mask in @v | ||
174 | */ | ||
175 | #ifndef atomic_set_mask | ||
176 | static inline void atomic_set_mask(unsigned int mask, atomic_t *v) | ||
177 | { | ||
178 | unsigned long flags; | ||
179 | |||
180 | raw_local_irq_save(flags); /* Don't trace it in a irqsoff handler */ | ||
181 | v->counter |= mask; | ||
182 | raw_local_irq_restore(flags); | ||
183 | } | ||
184 | #endif | ||
185 | 186 | ||
186 | #endif /* __KERNEL__ */ | ||
187 | #endif /* __ASM_GENERIC_ATOMIC_H */ | 187 | #endif /* __ASM_GENERIC_ATOMIC_H */ |
diff --git a/include/asm-generic/atomic64.h b/include/asm-generic/atomic64.h index b18ce4f9ee3d..30ad9c86cebb 100644 --- a/include/asm-generic/atomic64.h +++ b/include/asm-generic/atomic64.h | |||
@@ -20,10 +20,22 @@ typedef struct { | |||
20 | 20 | ||
21 | extern long long atomic64_read(const atomic64_t *v); | 21 | extern long long atomic64_read(const atomic64_t *v); |
22 | extern void atomic64_set(atomic64_t *v, long long i); | 22 | extern void atomic64_set(atomic64_t *v, long long i); |
23 | extern void atomic64_add(long long a, atomic64_t *v); | 23 | |
24 | extern long long atomic64_add_return(long long a, atomic64_t *v); | 24 | #define ATOMIC64_OP(op) \ |
25 | extern void atomic64_sub(long long a, atomic64_t *v); | 25 | extern void atomic64_##op(long long a, atomic64_t *v); |
26 | extern long long atomic64_sub_return(long long a, atomic64_t *v); | 26 | |
27 | #define ATOMIC64_OP_RETURN(op) \ | ||
28 | extern long long atomic64_##op##_return(long long a, atomic64_t *v); | ||
29 | |||
30 | #define ATOMIC64_OPS(op) ATOMIC64_OP(op) ATOMIC64_OP_RETURN(op) | ||
31 | |||
32 | ATOMIC64_OPS(add) | ||
33 | ATOMIC64_OPS(sub) | ||
34 | |||
35 | #undef ATOMIC64_OPS | ||
36 | #undef ATOMIC64_OP_RETURN | ||
37 | #undef ATOMIC64_OP | ||
38 | |||
27 | extern long long atomic64_dec_if_positive(atomic64_t *v); | 39 | extern long long atomic64_dec_if_positive(atomic64_t *v); |
28 | extern long long atomic64_cmpxchg(atomic64_t *v, long long o, long long n); | 40 | extern long long atomic64_cmpxchg(atomic64_t *v, long long o, long long n); |
29 | extern long long atomic64_xchg(atomic64_t *v, long long new); | 41 | extern long long atomic64_xchg(atomic64_t *v, long long new); |
diff --git a/lib/atomic64.c b/lib/atomic64.c index 08a4f068e61e..1298c05ef528 100644 --- a/lib/atomic64.c +++ b/lib/atomic64.c | |||
@@ -70,53 +70,42 @@ void atomic64_set(atomic64_t *v, long long i) | |||
70 | } | 70 | } |
71 | EXPORT_SYMBOL(atomic64_set); | 71 | EXPORT_SYMBOL(atomic64_set); |
72 | 72 | ||
73 | void atomic64_add(long long a, atomic64_t *v) | 73 | #define ATOMIC64_OP(op, c_op) \ |
74 | { | 74 | void atomic64_##op(long long a, atomic64_t *v) \ |
75 | unsigned long flags; | 75 | { \ |
76 | raw_spinlock_t *lock = lock_addr(v); | 76 | unsigned long flags; \ |
77 | 77 | raw_spinlock_t *lock = lock_addr(v); \ | |
78 | raw_spin_lock_irqsave(lock, flags); | 78 | \ |
79 | v->counter += a; | 79 | raw_spin_lock_irqsave(lock, flags); \ |
80 | raw_spin_unlock_irqrestore(lock, flags); | 80 | v->counter c_op a; \ |
81 | } | 81 | raw_spin_unlock_irqrestore(lock, flags); \ |
82 | EXPORT_SYMBOL(atomic64_add); | 82 | } \ |
83 | 83 | EXPORT_SYMBOL(atomic64_##op); | |
84 | long long atomic64_add_return(long long a, atomic64_t *v) | 84 | |
85 | { | 85 | #define ATOMIC64_OP_RETURN(op, c_op) \ |
86 | unsigned long flags; | 86 | long long atomic64_##op##_return(long long a, atomic64_t *v) \ |
87 | raw_spinlock_t *lock = lock_addr(v); | 87 | { \ |
88 | long long val; | 88 | unsigned long flags; \ |
89 | 89 | raw_spinlock_t *lock = lock_addr(v); \ | |
90 | raw_spin_lock_irqsave(lock, flags); | 90 | long long val; \ |
91 | val = v->counter += a; | 91 | \ |
92 | raw_spin_unlock_irqrestore(lock, flags); | 92 | raw_spin_lock_irqsave(lock, flags); \ |
93 | return val; | 93 | val = (v->counter c_op a); \ |
94 | } | 94 | raw_spin_unlock_irqrestore(lock, flags); \ |
95 | EXPORT_SYMBOL(atomic64_add_return); | 95 | return val; \ |
96 | 96 | } \ | |
97 | void atomic64_sub(long long a, atomic64_t *v) | 97 | EXPORT_SYMBOL(atomic64_##op##_return); |
98 | { | 98 | |
99 | unsigned long flags; | 99 | #define ATOMIC64_OPS(op, c_op) \ |
100 | raw_spinlock_t *lock = lock_addr(v); | 100 | ATOMIC64_OP(op, c_op) \ |
101 | 101 | ATOMIC64_OP_RETURN(op, c_op) | |
102 | raw_spin_lock_irqsave(lock, flags); | 102 | |
103 | v->counter -= a; | 103 | ATOMIC64_OPS(add, +=) |
104 | raw_spin_unlock_irqrestore(lock, flags); | 104 | ATOMIC64_OPS(sub, -=) |
105 | } | 105 | |
106 | EXPORT_SYMBOL(atomic64_sub); | 106 | #undef ATOMIC64_OPS |
107 | 107 | #undef ATOMIC64_OP_RETURN | |
108 | long long atomic64_sub_return(long long a, atomic64_t *v) | 108 | #undef ATOMIC64_OP |
109 | { | ||
110 | unsigned long flags; | ||
111 | raw_spinlock_t *lock = lock_addr(v); | ||
112 | long long val; | ||
113 | |||
114 | raw_spin_lock_irqsave(lock, flags); | ||
115 | val = v->counter -= a; | ||
116 | raw_spin_unlock_irqrestore(lock, flags); | ||
117 | return val; | ||
118 | } | ||
119 | EXPORT_SYMBOL(atomic64_sub_return); | ||
120 | 109 | ||
121 | long long atomic64_dec_if_positive(atomic64_t *v) | 110 | long long atomic64_dec_if_positive(atomic64_t *v) |
122 | { | 111 | { |