162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#ifndef _ASM_ARC_ATOMIC_SPLOCK_H 462306a36Sopenharmony_ci#define _ASM_ARC_ATOMIC_SPLOCK_H 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci/* 762306a36Sopenharmony_ci * Non hardware assisted Atomic-R-M-W 862306a36Sopenharmony_ci * Locking would change to irq-disabling only (UP) and spinlocks (SMP) 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistatic inline void arch_atomic_set(atomic_t *v, int i) 1262306a36Sopenharmony_ci{ 1362306a36Sopenharmony_ci /* 1462306a36Sopenharmony_ci * Independent of hardware support, all of the atomic_xxx() APIs need 1562306a36Sopenharmony_ci * to follow the same locking rules to make sure that a "hardware" 1662306a36Sopenharmony_ci * atomic insn (e.g. LD) doesn't clobber an "emulated" atomic insn 1762306a36Sopenharmony_ci * sequence 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * Thus atomic_set() despite being 1 insn (and seemingly atomic) 2062306a36Sopenharmony_ci * requires the locking. 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_ci unsigned long flags; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci atomic_ops_lock(flags); 2562306a36Sopenharmony_ci WRITE_ONCE(v->counter, i); 2662306a36Sopenharmony_ci atomic_ops_unlock(flags); 2762306a36Sopenharmony_ci} 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define arch_atomic_set_release(v, i) arch_atomic_set((v), (i)) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define ATOMIC_OP(op, c_op, asm_op) \ 3262306a36Sopenharmony_cistatic inline void arch_atomic_##op(int i, atomic_t *v) \ 3362306a36Sopenharmony_ci{ \ 3462306a36Sopenharmony_ci unsigned long flags; \ 3562306a36Sopenharmony_ci \ 3662306a36Sopenharmony_ci atomic_ops_lock(flags); \ 3762306a36Sopenharmony_ci v->counter c_op i; \ 3862306a36Sopenharmony_ci atomic_ops_unlock(flags); \ 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define ATOMIC_OP_RETURN(op, c_op, asm_op) \ 4262306a36Sopenharmony_cistatic inline int arch_atomic_##op##_return(int i, atomic_t *v) \ 4362306a36Sopenharmony_ci{ \ 4462306a36Sopenharmony_ci unsigned long flags; \ 4562306a36Sopenharmony_ci unsigned int temp; \ 4662306a36Sopenharmony_ci \ 4762306a36Sopenharmony_ci /* \ 4862306a36Sopenharmony_ci * spin lock/unlock provides the needed smp_mb() before/after \ 4962306a36Sopenharmony_ci */ \ 5062306a36Sopenharmony_ci atomic_ops_lock(flags); \ 5162306a36Sopenharmony_ci temp = v->counter; \ 5262306a36Sopenharmony_ci temp c_op i; \ 5362306a36Sopenharmony_ci v->counter = temp; \ 5462306a36Sopenharmony_ci atomic_ops_unlock(flags); \ 5562306a36Sopenharmony_ci \ 5662306a36Sopenharmony_ci return temp; \ 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#define ATOMIC_FETCH_OP(op, c_op, asm_op) \ 6062306a36Sopenharmony_cistatic inline int arch_atomic_fetch_##op(int i, atomic_t *v) \ 6162306a36Sopenharmony_ci{ \ 6262306a36Sopenharmony_ci unsigned long flags; \ 6362306a36Sopenharmony_ci unsigned int orig; \ 6462306a36Sopenharmony_ci \ 6562306a36Sopenharmony_ci /* \ 6662306a36Sopenharmony_ci * spin lock/unlock provides the needed smp_mb() before/after \ 6762306a36Sopenharmony_ci */ \ 6862306a36Sopenharmony_ci atomic_ops_lock(flags); \ 6962306a36Sopenharmony_ci orig = v->counter; \ 7062306a36Sopenharmony_ci v->counter c_op i; \ 7162306a36Sopenharmony_ci atomic_ops_unlock(flags); \ 7262306a36Sopenharmony_ci \ 7362306a36Sopenharmony_ci return orig; \ 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#define ATOMIC_OPS(op, c_op, asm_op) \ 7762306a36Sopenharmony_ci ATOMIC_OP(op, c_op, asm_op) \ 7862306a36Sopenharmony_ci ATOMIC_OP_RETURN(op, c_op, asm_op) \ 7962306a36Sopenharmony_ci ATOMIC_FETCH_OP(op, c_op, asm_op) 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ciATOMIC_OPS(add, +=, add) 8262306a36Sopenharmony_ciATOMIC_OPS(sub, -=, sub) 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci#define arch_atomic_fetch_add arch_atomic_fetch_add 8562306a36Sopenharmony_ci#define arch_atomic_fetch_sub arch_atomic_fetch_sub 8662306a36Sopenharmony_ci#define arch_atomic_add_return arch_atomic_add_return 8762306a36Sopenharmony_ci#define arch_atomic_sub_return arch_atomic_sub_return 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci#undef ATOMIC_OPS 9062306a36Sopenharmony_ci#define ATOMIC_OPS(op, c_op, asm_op) \ 9162306a36Sopenharmony_ci ATOMIC_OP(op, c_op, asm_op) \ 9262306a36Sopenharmony_ci ATOMIC_FETCH_OP(op, c_op, asm_op) 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ciATOMIC_OPS(and, &=, and) 9562306a36Sopenharmony_ciATOMIC_OPS(andnot, &= ~, bic) 9662306a36Sopenharmony_ciATOMIC_OPS(or, |=, or) 9762306a36Sopenharmony_ciATOMIC_OPS(xor, ^=, xor) 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci#define arch_atomic_andnot arch_atomic_andnot 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci#define arch_atomic_fetch_and arch_atomic_fetch_and 10262306a36Sopenharmony_ci#define arch_atomic_fetch_andnot arch_atomic_fetch_andnot 10362306a36Sopenharmony_ci#define arch_atomic_fetch_or arch_atomic_fetch_or 10462306a36Sopenharmony_ci#define arch_atomic_fetch_xor arch_atomic_fetch_xor 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci#undef ATOMIC_OPS 10762306a36Sopenharmony_ci#undef ATOMIC_FETCH_OP 10862306a36Sopenharmony_ci#undef ATOMIC_OP_RETURN 10962306a36Sopenharmony_ci#undef ATOMIC_OP 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci#endif 112