| /* SPDX-License-Identifier: GPL-2.0-only */ | |
| #ifndef _ASM_ARC_ATOMIC_SPLOCK_H | |
| #define _ASM_ARC_ATOMIC_SPLOCK_H | |
| /* | |
| * Non hardware assisted Atomic-R-M-W | |
| * Locking would change to irq-disabling only (UP) and spinlocks (SMP) | |
| */ | |
| static inline void arch_atomic_set(atomic_t *v, int i) | |
| { | |
| /* | |
| * Independent of hardware support, all of the atomic_xxx() APIs need | |
| * to follow the same locking rules to make sure that a "hardware" | |
| * atomic insn (e.g. LD) doesn't clobber an "emulated" atomic insn | |
| * sequence | |
| * | |
| * Thus atomic_set() despite being 1 insn (and seemingly atomic) | |
| * requires the locking. | |
| */ | |
| unsigned long flags; | |
| atomic_ops_lock(flags); | |
| WRITE_ONCE(v->counter, i); | |
| atomic_ops_unlock(flags); | |
| } | |
| #define arch_atomic_set_release(v, i) arch_atomic_set((v), (i)) | |
| #define ATOMIC_OP(op, c_op, asm_op) \ | |
| static inline void arch_atomic_##op(int i, atomic_t *v) \ | |
| { \ | |
| unsigned long flags; \ | |
| \ | |
| atomic_ops_lock(flags); \ | |
| v->counter c_op i; \ | |
| atomic_ops_unlock(flags); \ | |
| } | |
| #define ATOMIC_OP_RETURN(op, c_op, asm_op) \ | |
| static inline int arch_atomic_##op##_return(int i, atomic_t *v) \ | |
| { \ | |
| unsigned long flags; \ | |
| unsigned int temp; \ | |
| \ | |
| /* \ | |
| * spin lock/unlock provides the needed smp_mb() before/after \ | |
| */ \ | |
| atomic_ops_lock(flags); \ | |
| temp = v->counter; \ | |
| temp c_op i; \ | |
| v->counter = temp; \ | |
| atomic_ops_unlock(flags); \ | |
| \ | |
| return temp; \ | |
| } | |
| #define ATOMIC_FETCH_OP(op, c_op, asm_op) \ | |
| static inline int arch_atomic_fetch_##op(int i, atomic_t *v) \ | |
| { \ | |
| unsigned long flags; \ | |
| unsigned int orig; \ | |
| \ | |
| /* \ | |
| * spin lock/unlock provides the needed smp_mb() before/after \ | |
| */ \ | |
| atomic_ops_lock(flags); \ | |
| orig = v->counter; \ | |
| v->counter c_op i; \ | |
| atomic_ops_unlock(flags); \ | |
| \ | |
| return orig; \ | |
| } | |
| #define ATOMIC_OPS(op, c_op, asm_op) \ | |
| ATOMIC_OP(op, c_op, asm_op) \ | |
| ATOMIC_OP_RETURN(op, c_op, asm_op) \ | |
| ATOMIC_FETCH_OP(op, c_op, asm_op) | |
| ATOMIC_OPS(add, +=, add) | |
| ATOMIC_OPS(sub, -=, sub) | |
| #define arch_atomic_fetch_add arch_atomic_fetch_add | |
| #define arch_atomic_fetch_sub arch_atomic_fetch_sub | |
| #define arch_atomic_add_return arch_atomic_add_return | |
| #define arch_atomic_sub_return arch_atomic_sub_return | |
| #undef ATOMIC_OPS | |
| #define ATOMIC_OPS(op, c_op, asm_op) \ | |
| ATOMIC_OP(op, c_op, asm_op) \ | |
| ATOMIC_FETCH_OP(op, c_op, asm_op) | |
| ATOMIC_OPS(and, &=, and) | |
| ATOMIC_OPS(andnot, &= ~, bic) | |
| ATOMIC_OPS(or, |=, or) | |
| ATOMIC_OPS(xor, ^=, xor) | |
| #define arch_atomic_andnot arch_atomic_andnot | |
| #define arch_atomic_fetch_and arch_atomic_fetch_and | |
| #define arch_atomic_fetch_andnot arch_atomic_fetch_andnot | |
| #define arch_atomic_fetch_or arch_atomic_fetch_or | |
| #define arch_atomic_fetch_xor arch_atomic_fetch_xor | |
| #undef ATOMIC_OPS | |
| #undef ATOMIC_FETCH_OP | |
| #undef ATOMIC_OP_RETURN | |
| #undef ATOMIC_OP | |
| #endif |