1/* SPDX-License-Identifier: GPL-2.0 */ 2/* 3 * Copyright IBM Corp. 1999, 2016 4 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>, 5 * Denis Joseph Barrow, 6 * Arnd Bergmann, 7 */ 8 9#ifndef __ARCH_S390_ATOMIC__ 10#define __ARCH_S390_ATOMIC__ 11 12#include <linux/compiler.h> 13#include <linux/types.h> 14#include <asm/atomic_ops.h> 15#include <asm/barrier.h> 16#include <asm/cmpxchg.h> 17 18static inline int atomic_read(const atomic_t *v) 19{ 20 int c; 21 22 asm volatile( 23 " l %0,%1\n" 24 : "=d" (c) : "Q" (v->counter)); 25 return c; 26} 27 28static inline void atomic_set(atomic_t *v, int i) 29{ 30 asm volatile( 31 " st %1,%0\n" 32 : "=Q" (v->counter) : "d" (i)); 33} 34 35static inline int atomic_add_return(int i, atomic_t *v) 36{ 37 return __atomic_add_barrier(i, &v->counter) + i; 38} 39 40static inline int atomic_fetch_add(int i, atomic_t *v) 41{ 42 return __atomic_add_barrier(i, &v->counter); 43} 44 45static inline void atomic_add(int i, atomic_t *v) 46{ 47#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES 48 /* 49 * Order of conditions is important to circumvent gcc 10 bug: 50 * https://gcc.gnu.org/pipermail/gcc-patches/2020-July/549318.html 51 */ 52 if ((i > -129) && (i < 128) && __builtin_constant_p(i)) { 53 __atomic_add_const(i, &v->counter); 54 return; 55 } 56#endif 57 __atomic_add(i, &v->counter); 58} 59 60#define atomic_sub(_i, _v) atomic_add(-(int)(_i), _v) 61#define atomic_sub_return(_i, _v) atomic_add_return(-(int)(_i), _v) 62#define atomic_fetch_sub(_i, _v) atomic_fetch_add(-(int)(_i), _v) 63 64#define ATOMIC_OPS(op) \ 65static inline void atomic_##op(int i, atomic_t *v) \ 66{ \ 67 __atomic_##op(i, &v->counter); \ 68} \ 69static inline int atomic_fetch_##op(int i, atomic_t *v) \ 70{ \ 71 return __atomic_##op##_barrier(i, &v->counter); \ 72} 73 74ATOMIC_OPS(and) 75ATOMIC_OPS(or) 76ATOMIC_OPS(xor) 77 78#undef ATOMIC_OPS 79 80#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) 81 82static inline int atomic_cmpxchg(atomic_t *v, int old, int new) 83{ 84 return __atomic_cmpxchg(&v->counter, old, new); 85} 86 87#define ATOMIC64_INIT(i) { (i) } 88 89static inline s64 atomic64_read(const atomic64_t *v) 90{ 91 s64 c; 92 93 asm volatile( 94 " lg %0,%1\n" 95 : "=d" (c) : "Q" (v->counter)); 96 return c; 97} 98 99static inline void atomic64_set(atomic64_t *v, s64 i) 100{ 101 asm volatile( 102 " stg %1,%0\n" 103 : "=Q" (v->counter) : "d" (i)); 104} 105 106static inline s64 atomic64_add_return(s64 i, atomic64_t *v) 107{ 108 return __atomic64_add_barrier(i, (long *)&v->counter) + i; 109} 110 111static inline s64 atomic64_fetch_add(s64 i, atomic64_t *v) 112{ 113 return __atomic64_add_barrier(i, (long *)&v->counter); 114} 115 116static inline void atomic64_add(s64 i, atomic64_t *v) 117{ 118#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES 119 /* 120 * Order of conditions is important to circumvent gcc 10 bug: 121 * https://gcc.gnu.org/pipermail/gcc-patches/2020-July/549318.html 122 */ 123 if ((i > -129) && (i < 128) && __builtin_constant_p(i)) { 124 __atomic64_add_const(i, (long *)&v->counter); 125 return; 126 } 127#endif 128 __atomic64_add(i, (long *)&v->counter); 129} 130 131#define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) 132 133static inline s64 atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new) 134{ 135 return __atomic64_cmpxchg((long *)&v->counter, old, new); 136} 137 138#define ATOMIC64_OPS(op) \ 139static inline void atomic64_##op(s64 i, atomic64_t *v) \ 140{ \ 141 __atomic64_##op(i, (long *)&v->counter); \ 142} \ 143static inline long atomic64_fetch_##op(s64 i, atomic64_t *v) \ 144{ \ 145 return __atomic64_##op##_barrier(i, (long *)&v->counter); \ 146} 147 148ATOMIC64_OPS(and) 149ATOMIC64_OPS(or) 150ATOMIC64_OPS(xor) 151 152#undef ATOMIC64_OPS 153 154#define atomic64_sub_return(_i, _v) atomic64_add_return(-(s64)(_i), _v) 155#define atomic64_fetch_sub(_i, _v) atomic64_fetch_add(-(s64)(_i), _v) 156#define atomic64_sub(_i, _v) atomic64_add(-(s64)(_i), _v) 157 158#endif /* __ARCH_S390_ATOMIC__ */ 159