aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeiko Carstens <heiko.carstens@de.ibm.com>2014-03-20 03:55:00 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2014-04-01 03:23:35 -0400
commit0ccc8b7ac86053388e793bad20bd26bd777752eb (patch)
treeab5a74ecd88aba3d7060b2ff3cd7be60db8becc2
parentce1ce2f31224c18e84d859ccd5675cbb2728f57a (diff)
s390/bitops,atomic: add missing memory barriers
When reworking the bitops and atomic ops I missed that those instructions that got atomic behaviour only perform a "specific-operand-serialization" instead of a full "serialization". The compare-and-swap instruction used before performs a full serialization before and after the instruction is executed, which means it has full memory barrier semantics. In order to give the new bitops and atomic ops functions also full memory barrier semantics add a "bcr 14,0" before and after each of those new instructions which performs full serialization as well. This restores memory barrier semantics for bitops and atomic ops functions which return values, like e.g. atomic_add_return(), but not for functions which do not return a value, like e.g. atomic_add(). This is consistent to other architectures and what common code requires. Cc: stable@vger.kernel.org # v3.13+ Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/include/asm/atomic.h70
-rw-r--r--arch/s390/include/asm/bitops.h41
2 files changed, 65 insertions, 46 deletions
diff --git a/arch/s390/include/asm/atomic.h b/arch/s390/include/asm/atomic.h
index fa9aaf7144b7..1d4706114a45 100644
--- a/arch/s390/include/asm/atomic.h
+++ b/arch/s390/include/asm/atomic.h
@@ -15,23 +15,29 @@
15 15
16#include <linux/compiler.h> 16#include <linux/compiler.h>
17#include <linux/types.h> 17#include <linux/types.h>
18#include <asm/barrier.h>
18#include <asm/cmpxchg.h> 19#include <asm/cmpxchg.h>
19 20
20#define ATOMIC_INIT(i) { (i) } 21#define ATOMIC_INIT(i) { (i) }
21 22
23#define __ATOMIC_NO_BARRIER "\n"
24
22#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES 25#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
23 26
24#define __ATOMIC_OR "lao" 27#define __ATOMIC_OR "lao"
25#define __ATOMIC_AND "lan" 28#define __ATOMIC_AND "lan"
26#define __ATOMIC_ADD "laa" 29#define __ATOMIC_ADD "laa"
30#define __ATOMIC_BARRIER "bcr 14,0\n"
27 31
28#define __ATOMIC_LOOP(ptr, op_val, op_string) \ 32#define __ATOMIC_LOOP(ptr, op_val, op_string, __barrier) \
29({ \ 33({ \
30 int old_val; \ 34 int old_val; \
31 \ 35 \
32 typecheck(atomic_t *, ptr); \ 36 typecheck(atomic_t *, ptr); \
33 asm volatile( \ 37 asm volatile( \
38 __barrier \
34 op_string " %0,%2,%1\n" \ 39 op_string " %0,%2,%1\n" \
40 __barrier \
35 : "=d" (old_val), "+Q" ((ptr)->counter) \ 41 : "=d" (old_val), "+Q" ((ptr)->counter) \
36 : "d" (op_val) \ 42 : "d" (op_val) \
37 : "cc", "memory"); \ 43 : "cc", "memory"); \
@@ -43,8 +49,9 @@
43#define __ATOMIC_OR "or" 49#define __ATOMIC_OR "or"
44#define __ATOMIC_AND "nr" 50#define __ATOMIC_AND "nr"
45#define __ATOMIC_ADD "ar" 51#define __ATOMIC_ADD "ar"
52#define __ATOMIC_BARRIER "\n"
46 53
47#define __ATOMIC_LOOP(ptr, op_val, op_string) \ 54#define __ATOMIC_LOOP(ptr, op_val, op_string, __barrier) \
48({ \ 55({ \
49 int old_val, new_val; \ 56 int old_val, new_val; \
50 \ 57 \
@@ -82,7 +89,7 @@ static inline void atomic_set(atomic_t *v, int i)
82 89
83static inline int atomic_add_return(int i, atomic_t *v) 90static inline int atomic_add_return(int i, atomic_t *v)
84{ 91{
85 return __ATOMIC_LOOP(v, i, __ATOMIC_ADD) + i; 92 return __ATOMIC_LOOP(v, i, __ATOMIC_ADD, __ATOMIC_BARRIER) + i;
86} 93}
87 94
88static inline void atomic_add(int i, atomic_t *v) 95static inline void atomic_add(int i, atomic_t *v)
@@ -94,12 +101,10 @@ static inline void atomic_add(int i, atomic_t *v)
94 : "+Q" (v->counter) 101 : "+Q" (v->counter)
95 : "i" (i) 102 : "i" (i)
96 : "cc", "memory"); 103 : "cc", "memory");
97 } else { 104 return;
98 atomic_add_return(i, v);
99 } 105 }
100#else
101 atomic_add_return(i, v);
102#endif 106#endif
107 __ATOMIC_LOOP(v, i, __ATOMIC_ADD, __ATOMIC_NO_BARRIER);
103} 108}
104 109
105#define atomic_add_negative(_i, _v) (atomic_add_return(_i, _v) < 0) 110#define atomic_add_negative(_i, _v) (atomic_add_return(_i, _v) < 0)
@@ -115,12 +120,12 @@ static inline void atomic_add(int i, atomic_t *v)
115 120
116static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) 121static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
117{ 122{
118 __ATOMIC_LOOP(v, ~mask, __ATOMIC_AND); 123 __ATOMIC_LOOP(v, ~mask, __ATOMIC_AND, __ATOMIC_NO_BARRIER);
119} 124}
120 125
121static inline void atomic_set_mask(unsigned int mask, atomic_t *v) 126static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
122{ 127{
123 __ATOMIC_LOOP(v, mask, __ATOMIC_OR); 128 __ATOMIC_LOOP(v, mask, __ATOMIC_OR, __ATOMIC_NO_BARRIER);
124} 129}
125 130
126#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) 131#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
@@ -157,19 +162,24 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u)
157 162
158#ifdef CONFIG_64BIT 163#ifdef CONFIG_64BIT
159 164
165#define __ATOMIC64_NO_BARRIER "\n"
166
160#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES 167#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
161 168
162#define __ATOMIC64_OR "laog" 169#define __ATOMIC64_OR "laog"
163#define __ATOMIC64_AND "lang" 170#define __ATOMIC64_AND "lang"
164#define __ATOMIC64_ADD "laag" 171#define __ATOMIC64_ADD "laag"
172#define __ATOMIC64_BARRIER "bcr 14,0\n"
165 173
166#define __ATOMIC64_LOOP(ptr, op_val, op_string) \ 174#define __ATOMIC64_LOOP(ptr, op_val, op_string, __barrier) \
167({ \ 175({ \
168 long long old_val; \ 176 long long old_val; \
169 \ 177 \
170 typecheck(atomic64_t *, ptr); \ 178 typecheck(atomic64_t *, ptr); \
171 asm volatile( \ 179 asm volatile( \
180 __barrier \
172 op_string " %0,%2,%1\n" \ 181 op_string " %0,%2,%1\n" \
182 __barrier \
173 : "=d" (old_val), "+Q" ((ptr)->counter) \ 183 : "=d" (old_val), "+Q" ((ptr)->counter) \
174 : "d" (op_val) \ 184 : "d" (op_val) \
175 : "cc", "memory"); \ 185 : "cc", "memory"); \
@@ -181,8 +191,9 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u)
181#define __ATOMIC64_OR "ogr" 191#define __ATOMIC64_OR "ogr"
182#define __ATOMIC64_AND "ngr" 192#define __ATOMIC64_AND "ngr"
183#define __ATOMIC64_ADD "agr" 193#define __ATOMIC64_ADD "agr"
194#define __ATOMIC64_BARRIER "\n"
184 195
185#define __ATOMIC64_LOOP(ptr, op_val, op_string) \ 196#define __ATOMIC64_LOOP(ptr, op_val, op_string, __barrier) \
186({ \ 197({ \
187 long long old_val, new_val; \ 198 long long old_val, new_val; \
188 \ 199 \
@@ -220,17 +231,32 @@ static inline void atomic64_set(atomic64_t *v, long long i)
220 231
221static inline long long atomic64_add_return(long long i, atomic64_t *v) 232static inline long long atomic64_add_return(long long i, atomic64_t *v)
222{ 233{
223 return __ATOMIC64_LOOP(v, i, __ATOMIC64_ADD) + i; 234 return __ATOMIC64_LOOP(v, i, __ATOMIC64_ADD, __ATOMIC64_BARRIER) + i;
235}
236
237static inline void atomic64_add(long long i, atomic64_t *v)
238{
239#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
240 if (__builtin_constant_p(i) && (i > -129) && (i < 128)) {
241 asm volatile(
242 "agsi %0,%1\n"
243 : "+Q" (v->counter)
244 : "i" (i)
245 : "cc", "memory");
246 return;
247 }
248#endif
249 __ATOMIC64_LOOP(v, i, __ATOMIC64_ADD, __ATOMIC64_NO_BARRIER);
224} 250}
225 251
226static inline void atomic64_clear_mask(unsigned long mask, atomic64_t *v) 252static inline void atomic64_clear_mask(unsigned long mask, atomic64_t *v)
227{ 253{
228 __ATOMIC64_LOOP(v, ~mask, __ATOMIC64_AND); 254 __ATOMIC64_LOOP(v, ~mask, __ATOMIC64_AND, __ATOMIC64_NO_BARRIER);
229} 255}
230 256
231static inline void atomic64_set_mask(unsigned long mask, atomic64_t *v) 257static inline void atomic64_set_mask(unsigned long mask, atomic64_t *v)
232{ 258{
233 __ATOMIC64_LOOP(v, mask, __ATOMIC64_OR); 259 __ATOMIC64_LOOP(v, mask, __ATOMIC64_OR, __ATOMIC64_NO_BARRIER);
234} 260}
235 261
236#define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) 262#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
@@ -334,25 +360,13 @@ static inline void atomic64_clear_mask(unsigned long long mask, atomic64_t *v)
334 } while (atomic64_cmpxchg(v, old, new) != old); 360 } while (atomic64_cmpxchg(v, old, new) != old);
335} 361}
336 362
337#endif /* CONFIG_64BIT */
338
339static inline void atomic64_add(long long i, atomic64_t *v) 363static inline void atomic64_add(long long i, atomic64_t *v)
340{ 364{
341#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
342 if (__builtin_constant_p(i) && (i > -129) && (i < 128)) {
343 asm volatile(
344 "agsi %0,%1\n"
345 : "+Q" (v->counter)
346 : "i" (i)
347 : "cc", "memory");
348 } else {
349 atomic64_add_return(i, v);
350 }
351#else
352 atomic64_add_return(i, v); 365 atomic64_add_return(i, v);
353#endif
354} 366}
355 367
368#endif /* CONFIG_64BIT */
369
356static inline int atomic64_add_unless(atomic64_t *v, long long i, long long u) 370static inline int atomic64_add_unless(atomic64_t *v, long long i, long long u)
357{ 371{
358 long long c, old; 372 long long c, old;
diff --git a/arch/s390/include/asm/bitops.h b/arch/s390/include/asm/bitops.h
index ec5ef891db6b..520542477678 100644
--- a/arch/s390/include/asm/bitops.h
+++ b/arch/s390/include/asm/bitops.h
@@ -47,14 +47,18 @@
47 47
48#include <linux/typecheck.h> 48#include <linux/typecheck.h>
49#include <linux/compiler.h> 49#include <linux/compiler.h>
50#include <asm/barrier.h>
51
52#define __BITOPS_NO_BARRIER "\n"
50 53
51#ifndef CONFIG_64BIT 54#ifndef CONFIG_64BIT
52 55
53#define __BITOPS_OR "or" 56#define __BITOPS_OR "or"
54#define __BITOPS_AND "nr" 57#define __BITOPS_AND "nr"
55#define __BITOPS_XOR "xr" 58#define __BITOPS_XOR "xr"
59#define __BITOPS_BARRIER "\n"
56 60
57#define __BITOPS_LOOP(__addr, __val, __op_string) \ 61#define __BITOPS_LOOP(__addr, __val, __op_string, __barrier) \
58({ \ 62({ \
59 unsigned long __old, __new; \ 63 unsigned long __old, __new; \
60 \ 64 \
@@ -67,7 +71,7 @@
67 " jl 0b" \ 71 " jl 0b" \
68 : "=&d" (__old), "=&d" (__new), "+Q" (*(__addr))\ 72 : "=&d" (__old), "=&d" (__new), "+Q" (*(__addr))\
69 : "d" (__val) \ 73 : "d" (__val) \
70 : "cc"); \ 74 : "cc", "memory"); \
71 __old; \ 75 __old; \
72}) 76})
73 77
@@ -78,17 +82,20 @@
78#define __BITOPS_OR "laog" 82#define __BITOPS_OR "laog"
79#define __BITOPS_AND "lang" 83#define __BITOPS_AND "lang"
80#define __BITOPS_XOR "laxg" 84#define __BITOPS_XOR "laxg"
85#define __BITOPS_BARRIER "bcr 14,0\n"
81 86
82#define __BITOPS_LOOP(__addr, __val, __op_string) \ 87#define __BITOPS_LOOP(__addr, __val, __op_string, __barrier) \
83({ \ 88({ \
84 unsigned long __old; \ 89 unsigned long __old; \
85 \ 90 \
86 typecheck(unsigned long *, (__addr)); \ 91 typecheck(unsigned long *, (__addr)); \
87 asm volatile( \ 92 asm volatile( \
93 __barrier \
88 __op_string " %0,%2,%1\n" \ 94 __op_string " %0,%2,%1\n" \
95 __barrier \
89 : "=d" (__old), "+Q" (*(__addr)) \ 96 : "=d" (__old), "+Q" (*(__addr)) \
90 : "d" (__val) \ 97 : "d" (__val) \
91 : "cc"); \ 98 : "cc", "memory"); \
92 __old; \ 99 __old; \
93}) 100})
94 101
@@ -97,8 +104,9 @@
97#define __BITOPS_OR "ogr" 104#define __BITOPS_OR "ogr"
98#define __BITOPS_AND "ngr" 105#define __BITOPS_AND "ngr"
99#define __BITOPS_XOR "xgr" 106#define __BITOPS_XOR "xgr"
107#define __BITOPS_BARRIER "\n"
100 108
101#define __BITOPS_LOOP(__addr, __val, __op_string) \ 109#define __BITOPS_LOOP(__addr, __val, __op_string, __barrier) \
102({ \ 110({ \
103 unsigned long __old, __new; \ 111 unsigned long __old, __new; \
104 \ 112 \
@@ -111,7 +119,7 @@
111 " jl 0b" \ 119 " jl 0b" \
112 : "=&d" (__old), "=&d" (__new), "+Q" (*(__addr))\ 120 : "=&d" (__old), "=&d" (__new), "+Q" (*(__addr))\
113 : "d" (__val) \ 121 : "d" (__val) \
114 : "cc"); \ 122 : "cc", "memory"); \
115 __old; \ 123 __old; \
116}) 124})
117 125
@@ -149,12 +157,12 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *ptr)
149 "oi %0,%b1\n" 157 "oi %0,%b1\n"
150 : "+Q" (*caddr) 158 : "+Q" (*caddr)
151 : "i" (1 << (nr & 7)) 159 : "i" (1 << (nr & 7))
152 : "cc"); 160 : "cc", "memory");
153 return; 161 return;
154 } 162 }
155#endif 163#endif
156 mask = 1UL << (nr & (BITS_PER_LONG - 1)); 164 mask = 1UL << (nr & (BITS_PER_LONG - 1));
157 __BITOPS_LOOP(addr, mask, __BITOPS_OR); 165 __BITOPS_LOOP(addr, mask, __BITOPS_OR, __BITOPS_NO_BARRIER);
158} 166}
159 167
160static inline void clear_bit(unsigned long nr, volatile unsigned long *ptr) 168static inline void clear_bit(unsigned long nr, volatile unsigned long *ptr)
@@ -170,12 +178,12 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *ptr)
170 "ni %0,%b1\n" 178 "ni %0,%b1\n"
171 : "+Q" (*caddr) 179 : "+Q" (*caddr)
172 : "i" (~(1 << (nr & 7))) 180 : "i" (~(1 << (nr & 7)))
173 : "cc"); 181 : "cc", "memory");
174 return; 182 return;
175 } 183 }
176#endif 184#endif
177 mask = ~(1UL << (nr & (BITS_PER_LONG - 1))); 185 mask = ~(1UL << (nr & (BITS_PER_LONG - 1)));
178 __BITOPS_LOOP(addr, mask, __BITOPS_AND); 186 __BITOPS_LOOP(addr, mask, __BITOPS_AND, __BITOPS_NO_BARRIER);
179} 187}
180 188
181static inline void change_bit(unsigned long nr, volatile unsigned long *ptr) 189static inline void change_bit(unsigned long nr, volatile unsigned long *ptr)
@@ -191,12 +199,12 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *ptr)
191 "xi %0,%b1\n" 199 "xi %0,%b1\n"
192 : "+Q" (*caddr) 200 : "+Q" (*caddr)
193 : "i" (1 << (nr & 7)) 201 : "i" (1 << (nr & 7))
194 : "cc"); 202 : "cc", "memory");
195 return; 203 return;
196 } 204 }
197#endif 205#endif
198 mask = 1UL << (nr & (BITS_PER_LONG - 1)); 206 mask = 1UL << (nr & (BITS_PER_LONG - 1));
199 __BITOPS_LOOP(addr, mask, __BITOPS_XOR); 207 __BITOPS_LOOP(addr, mask, __BITOPS_XOR, __BITOPS_NO_BARRIER);
200} 208}
201 209
202static inline int 210static inline int
@@ -206,8 +214,7 @@ test_and_set_bit(unsigned long nr, volatile unsigned long *ptr)
206 unsigned long old, mask; 214 unsigned long old, mask;
207 215
208 mask = 1UL << (nr & (BITS_PER_LONG - 1)); 216 mask = 1UL << (nr & (BITS_PER_LONG - 1));
209 old = __BITOPS_LOOP(addr, mask, __BITOPS_OR); 217 old = __BITOPS_LOOP(addr, mask, __BITOPS_OR, __BITOPS_BARRIER);
210 barrier();
211 return (old & mask) != 0; 218 return (old & mask) != 0;
212} 219}
213 220
@@ -218,8 +225,7 @@ test_and_clear_bit(unsigned long nr, volatile unsigned long *ptr)
218 unsigned long old, mask; 225 unsigned long old, mask;
219 226
220 mask = ~(1UL << (nr & (BITS_PER_LONG - 1))); 227 mask = ~(1UL << (nr & (BITS_PER_LONG - 1)));
221 old = __BITOPS_LOOP(addr, mask, __BITOPS_AND); 228 old = __BITOPS_LOOP(addr, mask, __BITOPS_AND, __BITOPS_BARRIER);
222 barrier();
223 return (old & ~mask) != 0; 229 return (old & ~mask) != 0;
224} 230}
225 231
@@ -230,8 +236,7 @@ test_and_change_bit(unsigned long nr, volatile unsigned long *ptr)
230 unsigned long old, mask; 236 unsigned long old, mask;
231 237
232 mask = 1UL << (nr & (BITS_PER_LONG - 1)); 238 mask = 1UL << (nr & (BITS_PER_LONG - 1));
233 old = __BITOPS_LOOP(addr, mask, __BITOPS_XOR); 239 old = __BITOPS_LOOP(addr, mask, __BITOPS_XOR, __BITOPS_BARRIER);
234 barrier();
235 return (old & mask) != 0; 240 return (old & mask) != 0;
236} 241}
237 242