at v3.12 334 lines 7.5 kB view raw
1/* 2 * Copyright IBM Corp. 1999, 2009 3 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>, 4 * Denis Joseph Barrow, 5 * Arnd Bergmann <arndb@de.ibm.com>, 6 * 7 * Atomic operations that C can't guarantee us. 8 * Useful for resource counting etc. 9 * s390 uses 'Compare And Swap' for atomicity in SMP environment. 10 * 11 */ 12 13#ifndef __ARCH_S390_ATOMIC__ 14#define __ARCH_S390_ATOMIC__ 15 16#include <linux/compiler.h> 17#include <linux/types.h> 18#include <asm/cmpxchg.h> 19 20#define ATOMIC_INIT(i) { (i) } 21 22#define __CS_LOOP(ptr, op_val, op_string) ({ \ 23 int old_val, new_val; \ 24 asm volatile( \ 25 " l %0,%2\n" \ 26 "0: lr %1,%0\n" \ 27 op_string " %1,%3\n" \ 28 " cs %0,%1,%2\n" \ 29 " jl 0b" \ 30 : "=&d" (old_val), "=&d" (new_val), \ 31 "=Q" (((atomic_t *)(ptr))->counter) \ 32 : "d" (op_val), "Q" (((atomic_t *)(ptr))->counter) \ 33 : "cc", "memory"); \ 34 new_val; \ 35}) 36 37static inline int atomic_read(const atomic_t *v) 38{ 39 int c; 40 41 asm volatile( 42 " l %0,%1\n" 43 : "=d" (c) : "Q" (v->counter)); 44 return c; 45} 46 47static inline void atomic_set(atomic_t *v, int i) 48{ 49 asm volatile( 50 " st %1,%0\n" 51 : "=Q" (v->counter) : "d" (i)); 52} 53 54static inline int atomic_add_return(int i, atomic_t *v) 55{ 56 return __CS_LOOP(v, i, "ar"); 57} 58#define atomic_add(_i, _v) atomic_add_return(_i, _v) 59#define atomic_add_negative(_i, _v) (atomic_add_return(_i, _v) < 0) 60#define atomic_inc(_v) atomic_add_return(1, _v) 61#define atomic_inc_return(_v) atomic_add_return(1, _v) 62#define atomic_inc_and_test(_v) (atomic_add_return(1, _v) == 0) 63 64static inline int atomic_sub_return(int i, atomic_t *v) 65{ 66 return __CS_LOOP(v, i, "sr"); 67} 68#define atomic_sub(_i, _v) atomic_sub_return(_i, _v) 69#define atomic_sub_and_test(_i, _v) (atomic_sub_return(_i, _v) == 0) 70#define atomic_dec(_v) atomic_sub_return(1, _v) 71#define atomic_dec_return(_v) atomic_sub_return(1, _v) 72#define atomic_dec_and_test(_v) (atomic_sub_return(1, _v) == 0) 73 74static inline void atomic_clear_mask(unsigned long mask, atomic_t *v) 75{ 76 __CS_LOOP(v, ~mask, "nr"); 77} 78 79static inline void atomic_set_mask(unsigned long mask, atomic_t *v) 80{ 81 __CS_LOOP(v, mask, "or"); 82} 83 84#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) 85 86static inline int atomic_cmpxchg(atomic_t *v, int old, int new) 87{ 88 asm volatile( 89 " cs %0,%2,%1" 90 : "+d" (old), "=Q" (v->counter) 91 : "d" (new), "Q" (v->counter) 92 : "cc", "memory"); 93 return old; 94} 95 96static inline int __atomic_add_unless(atomic_t *v, int a, int u) 97{ 98 int c, old; 99 c = atomic_read(v); 100 for (;;) { 101 if (unlikely(c == u)) 102 break; 103 old = atomic_cmpxchg(v, c, c + a); 104 if (likely(old == c)) 105 break; 106 c = old; 107 } 108 return c; 109} 110 111 112#undef __CS_LOOP 113 114#define ATOMIC64_INIT(i) { (i) } 115 116#ifdef CONFIG_64BIT 117 118#define __CSG_LOOP(ptr, op_val, op_string) ({ \ 119 long long old_val, new_val; \ 120 asm volatile( \ 121 " lg %0,%2\n" \ 122 "0: lgr %1,%0\n" \ 123 op_string " %1,%3\n" \ 124 " csg %0,%1,%2\n" \ 125 " jl 0b" \ 126 : "=&d" (old_val), "=&d" (new_val), \ 127 "=Q" (((atomic_t *)(ptr))->counter) \ 128 : "d" (op_val), "Q" (((atomic_t *)(ptr))->counter) \ 129 : "cc", "memory"); \ 130 new_val; \ 131}) 132 133static inline long long atomic64_read(const atomic64_t *v) 134{ 135 long long c; 136 137 asm volatile( 138 " lg %0,%1\n" 139 : "=d" (c) : "Q" (v->counter)); 140 return c; 141} 142 143static inline void atomic64_set(atomic64_t *v, long long i) 144{ 145 asm volatile( 146 " stg %1,%0\n" 147 : "=Q" (v->counter) : "d" (i)); 148} 149 150static inline long long atomic64_add_return(long long i, atomic64_t *v) 151{ 152 return __CSG_LOOP(v, i, "agr"); 153} 154 155static inline long long atomic64_sub_return(long long i, atomic64_t *v) 156{ 157 return __CSG_LOOP(v, i, "sgr"); 158} 159 160static inline void atomic64_clear_mask(unsigned long mask, atomic64_t *v) 161{ 162 __CSG_LOOP(v, ~mask, "ngr"); 163} 164 165static inline void atomic64_set_mask(unsigned long mask, atomic64_t *v) 166{ 167 __CSG_LOOP(v, mask, "ogr"); 168} 169 170#define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) 171 172static inline long long atomic64_cmpxchg(atomic64_t *v, 173 long long old, long long new) 174{ 175 asm volatile( 176 " csg %0,%2,%1" 177 : "+d" (old), "=Q" (v->counter) 178 : "d" (new), "Q" (v->counter) 179 : "cc", "memory"); 180 return old; 181} 182 183#undef __CSG_LOOP 184 185#else /* CONFIG_64BIT */ 186 187typedef struct { 188 long long counter; 189} atomic64_t; 190 191static inline long long atomic64_read(const atomic64_t *v) 192{ 193 register_pair rp; 194 195 asm volatile( 196 " lm %0,%N0,%1" 197 : "=&d" (rp) : "Q" (v->counter) ); 198 return rp.pair; 199} 200 201static inline void atomic64_set(atomic64_t *v, long long i) 202{ 203 register_pair rp = {.pair = i}; 204 205 asm volatile( 206 " stm %1,%N1,%0" 207 : "=Q" (v->counter) : "d" (rp) ); 208} 209 210static inline long long atomic64_xchg(atomic64_t *v, long long new) 211{ 212 register_pair rp_new = {.pair = new}; 213 register_pair rp_old; 214 215 asm volatile( 216 " lm %0,%N0,%1\n" 217 "0: cds %0,%2,%1\n" 218 " jl 0b\n" 219 : "=&d" (rp_old), "=Q" (v->counter) 220 : "d" (rp_new), "Q" (v->counter) 221 : "cc"); 222 return rp_old.pair; 223} 224 225static inline long long atomic64_cmpxchg(atomic64_t *v, 226 long long old, long long new) 227{ 228 register_pair rp_old = {.pair = old}; 229 register_pair rp_new = {.pair = new}; 230 231 asm volatile( 232 " cds %0,%2,%1" 233 : "+&d" (rp_old), "=Q" (v->counter) 234 : "d" (rp_new), "Q" (v->counter) 235 : "cc"); 236 return rp_old.pair; 237} 238 239 240static inline long long atomic64_add_return(long long i, atomic64_t *v) 241{ 242 long long old, new; 243 244 do { 245 old = atomic64_read(v); 246 new = old + i; 247 } while (atomic64_cmpxchg(v, old, new) != old); 248 return new; 249} 250 251static inline long long atomic64_sub_return(long long i, atomic64_t *v) 252{ 253 long long old, new; 254 255 do { 256 old = atomic64_read(v); 257 new = old - i; 258 } while (atomic64_cmpxchg(v, old, new) != old); 259 return new; 260} 261 262static inline void atomic64_set_mask(unsigned long long mask, atomic64_t *v) 263{ 264 long long old, new; 265 266 do { 267 old = atomic64_read(v); 268 new = old | mask; 269 } while (atomic64_cmpxchg(v, old, new) != old); 270} 271 272static inline void atomic64_clear_mask(unsigned long long mask, atomic64_t *v) 273{ 274 long long old, new; 275 276 do { 277 old = atomic64_read(v); 278 new = old & mask; 279 } while (atomic64_cmpxchg(v, old, new) != old); 280} 281 282#endif /* CONFIG_64BIT */ 283 284static inline int atomic64_add_unless(atomic64_t *v, long long a, long long u) 285{ 286 long long c, old; 287 288 c = atomic64_read(v); 289 for (;;) { 290 if (unlikely(c == u)) 291 break; 292 old = atomic64_cmpxchg(v, c, c + a); 293 if (likely(old == c)) 294 break; 295 c = old; 296 } 297 return c != u; 298} 299 300static inline long long atomic64_dec_if_positive(atomic64_t *v) 301{ 302 long long c, old, dec; 303 304 c = atomic64_read(v); 305 for (;;) { 306 dec = c - 1; 307 if (unlikely(dec < 0)) 308 break; 309 old = atomic64_cmpxchg((v), c, dec); 310 if (likely(old == c)) 311 break; 312 c = old; 313 } 314 return dec; 315} 316 317#define atomic64_add(_i, _v) atomic64_add_return(_i, _v) 318#define atomic64_add_negative(_i, _v) (atomic64_add_return(_i, _v) < 0) 319#define atomic64_inc(_v) atomic64_add_return(1, _v) 320#define atomic64_inc_return(_v) atomic64_add_return(1, _v) 321#define atomic64_inc_and_test(_v) (atomic64_add_return(1, _v) == 0) 322#define atomic64_sub(_i, _v) atomic64_sub_return(_i, _v) 323#define atomic64_sub_and_test(_i, _v) (atomic64_sub_return(_i, _v) == 0) 324#define atomic64_dec(_v) atomic64_sub_return(1, _v) 325#define atomic64_dec_return(_v) atomic64_sub_return(1, _v) 326#define atomic64_dec_and_test(_v) (atomic64_sub_return(1, _v) == 0) 327#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) 328 329#define smp_mb__before_atomic_dec() smp_mb() 330#define smp_mb__after_atomic_dec() smp_mb() 331#define smp_mb__before_atomic_inc() smp_mb() 332#define smp_mb__after_atomic_inc() smp_mb() 333 334#endif /* __ARCH_S390_ATOMIC__ */