1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) 4 */ 5 6 #ifndef __ASM_ARC_CMPXCHG_H 7 #define __ASM_ARC_CMPXCHG_H 8 9 #include <linux/build_bug.h> 10 #include <linux/types.h> 11 #include <linux/cmpxchg-emu.h> 12 13 #include <asm/barrier.h> 14 #include <asm/smp.h> 15 16 #ifdef CONFIG_ARC_HAS_LLSC 17 18 /* 19 * if (*ptr == @old) 20 * *ptr = @new 21 */ 22 #define __cmpxchg(ptr, old, new) \ 23 ({ \ 24 __typeof__(*(ptr)) _prev; \ 25 \ 26 __asm__ __volatile__( \ 27 "1: llock %0, [%1] \n" \ 28 " brne %0, %2, 2f \n" \ 29 " scond %3, [%1] \n" \ 30 " bnz 1b \n" \ 31 "2: \n" \ 32 : "=&r"(_prev) /* Early clobber prevent reg reuse */ \ 33 : "r"(ptr), /* Not "m": llock only supports reg */ \ 34 "ir"(old), \ 35 "r"(new) /* Not "ir": scond can't take LIMM */ \ 36 : "cc", \ 37 "memory"); /* gcc knows memory is clobbered */ \ 38 \ 39 _prev; \ 40 }) 41 42 #define arch_cmpxchg_relaxed(ptr, old, new) \ 43 ({ \ 44 __typeof__(ptr) _p_ = (ptr); \ 45 __typeof__(*(ptr)) _o_ = (old); \ 46 __typeof__(*(ptr)) _n_ = (new); \ 47 __typeof__(*(ptr)) _prev_; \ 48 \ 49 switch (sizeof(*(_p_))) { \ 50 case 1: \ 51 _prev_ = (__typeof__(*(ptr)))cmpxchg_emu_u8((volatile u8 *__force)_p_, (uintptr_t)_o_, (uintptr_t)_n_); \ 52 break; \ 53 case 4: \ 54 _prev_ = __cmpxchg(_p_, _o_, _n_); \ 55 break; \ 56 default: \ 57 BUILD_BUG(); \ 58 } \ 59 _prev_; \ 60 }) 61 62 #define arch_cmpxchg_local arch_cmpxchg_relaxed 63 64 #else 65 66 #define arch_cmpxchg(ptr, old, new) \ 67 ({ \ 68 volatile __typeof__(ptr) _p_ = (ptr); \ 69 __typeof__(*(ptr)) _o_ = (old); \ 70 __typeof__(*(ptr)) _n_ = (new); \ 71 __typeof__(*(ptr)) _prev_; \ 72 unsigned long __flags; \ 73 \ 74 /* \ 75 * spin lock/unlock provide the needed smp_mb() before/after \ 76 */ \ 77 atomic_ops_lock(__flags); \ 78 _prev_ = *_p_; \ 79 if (_prev_ == _o_) \ 80 *_p_ = _n_; \ 81 atomic_ops_unlock(__flags); \ 82 _prev_; \ 83 }) 84 85 #define arch_cmpxchg_local arch_cmpxchg 86 87 #endif 88 89 /* 90 * xchg 91 */ 92 #ifdef CONFIG_ARC_HAS_LLSC 93 94 #define __arch_xchg(ptr, val) \ 95 ({ \ 96 __asm__ __volatile__( \ 97 " ex %0, [%1] \n" /* set new value */ \ 98 : "+r"(val) \ 99 : "r"(ptr) \ 100 : "memory"); \ 101 _val_; /* get old value */ \ 102 }) 103 104 #define arch_xchg_relaxed(ptr, val) \ 105 ({ \ 106 __typeof__(ptr) _p_ = (ptr); \ 107 __typeof__(*(ptr)) _val_ = (val); \ 108 \ 109 switch (sizeof(*(_p_))) { \ 110 case 4: \ 111 _val_ = __arch_xchg(_p_, _val_); \ 112 break; \ 113 default: \ 114 BUILD_BUG(); \ 115 } \ 116 _val_; \ 117 }) 118 119 #else /* !CONFIG_ARC_HAS_LLSC */ 120 121 /* 122 * EX instructions is baseline and present in !LLSC too. But in this 123 * regime it still needs use @atomic_ops_lock spinlock to allow interop 124 * with cmpxchg() which uses spinlock in !LLSC 125 * (llist.h use xchg and cmpxchg on sama data) 126 */ 127 128 #define arch_xchg(ptr, val) \ 129 ({ \ 130 __typeof__(ptr) _p_ = (ptr); \ 131 __typeof__(*(ptr)) _val_ = (val); \ 132 \ 133 unsigned long __flags; \ 134 \ 135 atomic_ops_lock(__flags); \ 136 \ 137 __asm__ __volatile__( \ 138 " ex %0, [%1] \n" \ 139 : "+r"(_val_) \ 140 : "r"(_p_) \ 141 : "memory"); \ 142 \ 143 atomic_ops_unlock(__flags); \ 144 _val_; \ 145 }) 146 147 #endif 148 149 #endif 150