18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci#ifndef _ARCH_POWERPC_LOCAL_H 38c2ecf20Sopenharmony_ci#define _ARCH_POWERPC_LOCAL_H 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/percpu.h> 88c2ecf20Sopenharmony_ci#include <linux/atomic.h> 98c2ecf20Sopenharmony_ci#include <linux/irqflags.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <asm/hw_irq.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_citypedef struct 148c2ecf20Sopenharmony_ci{ 158c2ecf20Sopenharmony_ci long v; 168c2ecf20Sopenharmony_ci} local_t; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define LOCAL_INIT(i) { (i) } 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic __inline__ long local_read(const local_t *l) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci return READ_ONCE(l->v); 238c2ecf20Sopenharmony_ci} 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic __inline__ void local_set(local_t *l, long i) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci WRITE_ONCE(l->v, i); 288c2ecf20Sopenharmony_ci} 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define LOCAL_OP(op, c_op) \ 318c2ecf20Sopenharmony_cistatic __inline__ void local_##op(long i, local_t *l) \ 328c2ecf20Sopenharmony_ci{ \ 338c2ecf20Sopenharmony_ci unsigned long flags; \ 348c2ecf20Sopenharmony_ci \ 358c2ecf20Sopenharmony_ci powerpc_local_irq_pmu_save(flags); \ 368c2ecf20Sopenharmony_ci l->v c_op i; \ 378c2ecf20Sopenharmony_ci powerpc_local_irq_pmu_restore(flags); \ 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define LOCAL_OP_RETURN(op, c_op) \ 418c2ecf20Sopenharmony_cistatic __inline__ long local_##op##_return(long a, local_t *l) \ 428c2ecf20Sopenharmony_ci{ \ 438c2ecf20Sopenharmony_ci long t; \ 448c2ecf20Sopenharmony_ci unsigned long flags; \ 458c2ecf20Sopenharmony_ci \ 468c2ecf20Sopenharmony_ci powerpc_local_irq_pmu_save(flags); \ 478c2ecf20Sopenharmony_ci t = (l->v c_op a); \ 488c2ecf20Sopenharmony_ci powerpc_local_irq_pmu_restore(flags); \ 498c2ecf20Sopenharmony_ci \ 508c2ecf20Sopenharmony_ci return t; \ 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define LOCAL_OPS(op, c_op) \ 548c2ecf20Sopenharmony_ci LOCAL_OP(op, c_op) \ 558c2ecf20Sopenharmony_ci LOCAL_OP_RETURN(op, c_op) 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ciLOCAL_OPS(add, +=) 588c2ecf20Sopenharmony_ciLOCAL_OPS(sub, -=) 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define local_add_negative(a, l) (local_add_return((a), (l)) < 0) 618c2ecf20Sopenharmony_ci#define local_inc_return(l) local_add_return(1LL, l) 628c2ecf20Sopenharmony_ci#define local_inc(l) local_inc_return(l) 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* 658c2ecf20Sopenharmony_ci * local_inc_and_test - increment and test 668c2ecf20Sopenharmony_ci * @l: pointer of type local_t 678c2ecf20Sopenharmony_ci * 688c2ecf20Sopenharmony_ci * Atomically increments @l by 1 698c2ecf20Sopenharmony_ci * and returns true if the result is zero, or false for all 708c2ecf20Sopenharmony_ci * other cases. 718c2ecf20Sopenharmony_ci */ 728c2ecf20Sopenharmony_ci#define local_inc_and_test(l) (local_inc_return(l) == 0) 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#define local_dec_return(l) local_sub_return(1LL, l) 758c2ecf20Sopenharmony_ci#define local_dec(l) local_dec_return(l) 768c2ecf20Sopenharmony_ci#define local_sub_and_test(a, l) (local_sub_return((a), (l)) == 0) 778c2ecf20Sopenharmony_ci#define local_dec_and_test(l) (local_dec_return((l)) == 0) 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic __inline__ long local_cmpxchg(local_t *l, long o, long n) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci long t; 828c2ecf20Sopenharmony_ci unsigned long flags; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci powerpc_local_irq_pmu_save(flags); 858c2ecf20Sopenharmony_ci t = l->v; 868c2ecf20Sopenharmony_ci if (t == o) 878c2ecf20Sopenharmony_ci l->v = n; 888c2ecf20Sopenharmony_ci powerpc_local_irq_pmu_restore(flags); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci return t; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic __inline__ long local_xchg(local_t *l, long n) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci long t; 968c2ecf20Sopenharmony_ci unsigned long flags; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci powerpc_local_irq_pmu_save(flags); 998c2ecf20Sopenharmony_ci t = l->v; 1008c2ecf20Sopenharmony_ci l->v = n; 1018c2ecf20Sopenharmony_ci powerpc_local_irq_pmu_restore(flags); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci return t; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/** 1078c2ecf20Sopenharmony_ci * local_add_unless - add unless the number is a given value 1088c2ecf20Sopenharmony_ci * @l: pointer of type local_t 1098c2ecf20Sopenharmony_ci * @a: the amount to add to v... 1108c2ecf20Sopenharmony_ci * @u: ...unless v is equal to u. 1118c2ecf20Sopenharmony_ci * 1128c2ecf20Sopenharmony_ci * Atomically adds @a to @l, so long as it was not @u. 1138c2ecf20Sopenharmony_ci * Returns non-zero if @l was not @u, and zero otherwise. 1148c2ecf20Sopenharmony_ci */ 1158c2ecf20Sopenharmony_cistatic __inline__ int local_add_unless(local_t *l, long a, long u) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci unsigned long flags; 1188c2ecf20Sopenharmony_ci int ret = 0; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci powerpc_local_irq_pmu_save(flags); 1218c2ecf20Sopenharmony_ci if (l->v != u) { 1228c2ecf20Sopenharmony_ci l->v += a; 1238c2ecf20Sopenharmony_ci ret = 1; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci powerpc_local_irq_pmu_restore(flags); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci return ret; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci#define local_inc_not_zero(l) local_add_unless((l), 1, 0) 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci/* Use these for per-cpu local_t variables: on some archs they are 1338c2ecf20Sopenharmony_ci * much more efficient than these naive implementations. Note they take 1348c2ecf20Sopenharmony_ci * a variable, not an address. 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci#define __local_inc(l) ((l)->v++) 1388c2ecf20Sopenharmony_ci#define __local_dec(l) ((l)->v++) 1398c2ecf20Sopenharmony_ci#define __local_add(i,l) ((l)->v+=(i)) 1408c2ecf20Sopenharmony_ci#define __local_sub(i,l) ((l)->v-=(i)) 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci#else /* CONFIG_PPC64 */ 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci#include <asm-generic/local.h> 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC64 */ 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci#endif /* _ARCH_POWERPC_LOCAL_H */ 149