18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright IBM Corp. 1999, 2016 48c2ecf20Sopenharmony_ci * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>, 58c2ecf20Sopenharmony_ci * Denis Joseph Barrow, 68c2ecf20Sopenharmony_ci * Arnd Bergmann, 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#ifndef __ARCH_S390_ATOMIC__ 108c2ecf20Sopenharmony_ci#define __ARCH_S390_ATOMIC__ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/compiler.h> 138c2ecf20Sopenharmony_ci#include <linux/types.h> 148c2ecf20Sopenharmony_ci#include <asm/atomic_ops.h> 158c2ecf20Sopenharmony_ci#include <asm/barrier.h> 168c2ecf20Sopenharmony_ci#include <asm/cmpxchg.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic inline int atomic_read(const atomic_t *v) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci int c; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci asm volatile( 238c2ecf20Sopenharmony_ci " l %0,%1\n" 248c2ecf20Sopenharmony_ci : "=d" (c) : "Q" (v->counter)); 258c2ecf20Sopenharmony_ci return c; 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic inline void atomic_set(atomic_t *v, int i) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci asm volatile( 318c2ecf20Sopenharmony_ci " st %1,%0\n" 328c2ecf20Sopenharmony_ci : "=Q" (v->counter) : "d" (i)); 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic inline int atomic_add_return(int i, atomic_t *v) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci return __atomic_add_barrier(i, &v->counter) + i; 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic inline int atomic_fetch_add(int i, atomic_t *v) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci return __atomic_add_barrier(i, &v->counter); 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic inline void atomic_add(int i, atomic_t *v) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES 488c2ecf20Sopenharmony_ci /* 498c2ecf20Sopenharmony_ci * Order of conditions is important to circumvent gcc 10 bug: 508c2ecf20Sopenharmony_ci * https://gcc.gnu.org/pipermail/gcc-patches/2020-July/549318.html 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_ci if ((i > -129) && (i < 128) && __builtin_constant_p(i)) { 538c2ecf20Sopenharmony_ci __atomic_add_const(i, &v->counter); 548c2ecf20Sopenharmony_ci return; 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci#endif 578c2ecf20Sopenharmony_ci __atomic_add(i, &v->counter); 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define atomic_sub(_i, _v) atomic_add(-(int)(_i), _v) 618c2ecf20Sopenharmony_ci#define atomic_sub_return(_i, _v) atomic_add_return(-(int)(_i), _v) 628c2ecf20Sopenharmony_ci#define atomic_fetch_sub(_i, _v) atomic_fetch_add(-(int)(_i), _v) 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define ATOMIC_OPS(op) \ 658c2ecf20Sopenharmony_cistatic inline void atomic_##op(int i, atomic_t *v) \ 668c2ecf20Sopenharmony_ci{ \ 678c2ecf20Sopenharmony_ci __atomic_##op(i, &v->counter); \ 688c2ecf20Sopenharmony_ci} \ 698c2ecf20Sopenharmony_cistatic inline int atomic_fetch_##op(int i, atomic_t *v) \ 708c2ecf20Sopenharmony_ci{ \ 718c2ecf20Sopenharmony_ci return __atomic_##op##_barrier(i, &v->counter); \ 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ciATOMIC_OPS(and) 758c2ecf20Sopenharmony_ciATOMIC_OPS(or) 768c2ecf20Sopenharmony_ciATOMIC_OPS(xor) 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci#undef ATOMIC_OPS 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic inline int atomic_cmpxchg(atomic_t *v, int old, int new) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci return __atomic_cmpxchg(&v->counter, old, new); 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci#define ATOMIC64_INIT(i) { (i) } 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic inline s64 atomic64_read(const atomic64_t *v) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci s64 c; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci asm volatile( 948c2ecf20Sopenharmony_ci " lg %0,%1\n" 958c2ecf20Sopenharmony_ci : "=d" (c) : "Q" (v->counter)); 968c2ecf20Sopenharmony_ci return c; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic inline void atomic64_set(atomic64_t *v, s64 i) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci asm volatile( 1028c2ecf20Sopenharmony_ci " stg %1,%0\n" 1038c2ecf20Sopenharmony_ci : "=Q" (v->counter) : "d" (i)); 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic inline s64 atomic64_add_return(s64 i, atomic64_t *v) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci return __atomic64_add_barrier(i, (long *)&v->counter) + i; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic inline s64 atomic64_fetch_add(s64 i, atomic64_t *v) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci return __atomic64_add_barrier(i, (long *)&v->counter); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic inline void atomic64_add(s64 i, atomic64_t *v) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES 1198c2ecf20Sopenharmony_ci /* 1208c2ecf20Sopenharmony_ci * Order of conditions is important to circumvent gcc 10 bug: 1218c2ecf20Sopenharmony_ci * https://gcc.gnu.org/pipermail/gcc-patches/2020-July/549318.html 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ci if ((i > -129) && (i < 128) && __builtin_constant_p(i)) { 1248c2ecf20Sopenharmony_ci __atomic64_add_const(i, (long *)&v->counter); 1258c2ecf20Sopenharmony_ci return; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci#endif 1288c2ecf20Sopenharmony_ci __atomic64_add(i, (long *)&v->counter); 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci#define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic inline s64 atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci return __atomic64_cmpxchg((long *)&v->counter, old, new); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci#define ATOMIC64_OPS(op) \ 1398c2ecf20Sopenharmony_cistatic inline void atomic64_##op(s64 i, atomic64_t *v) \ 1408c2ecf20Sopenharmony_ci{ \ 1418c2ecf20Sopenharmony_ci __atomic64_##op(i, (long *)&v->counter); \ 1428c2ecf20Sopenharmony_ci} \ 1438c2ecf20Sopenharmony_cistatic inline long atomic64_fetch_##op(s64 i, atomic64_t *v) \ 1448c2ecf20Sopenharmony_ci{ \ 1458c2ecf20Sopenharmony_ci return __atomic64_##op##_barrier(i, (long *)&v->counter); \ 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ciATOMIC64_OPS(and) 1498c2ecf20Sopenharmony_ciATOMIC64_OPS(or) 1508c2ecf20Sopenharmony_ciATOMIC64_OPS(xor) 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci#undef ATOMIC64_OPS 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci#define atomic64_sub_return(_i, _v) atomic64_add_return(-(s64)(_i), _v) 1558c2ecf20Sopenharmony_ci#define atomic64_fetch_sub(_i, _v) atomic64_fetch_add(-(s64)(_i), _v) 1568c2ecf20Sopenharmony_ci#define atomic64_sub(_i, _v) atomic64_add(-(s64)(_i), _v) 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci#endif /* __ARCH_S390_ATOMIC__ */ 159