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 2: \ 54 _prev_ = (__typeof__(*(ptr)))cmpxchg_emu_u16((volatile u16 *__force)_p_, (unsigned long)_o_, (unsigned long)_n_); \ 55 break; \ 56 case 4: \ 57 _prev_ = __cmpxchg(_p_, _o_, _n_); \ 58 break; \ 59 default: \ 60 BUILD_BUG(); \ 61 } \ 62 _prev_; \ 63 }) 64 65 #else 66 67 #define arch_cmpxchg(ptr, old, new) \ 68 ({ \ 69 volatile __typeof__(ptr) _p_ = (ptr); \ 70 __typeof__(*(ptr)) _o_ = (old); \ 71 __typeof__(*(ptr)) _n_ = (new); \ 72 __typeof__(*(ptr)) _prev_; \ 73 unsigned long __flags; \ 74 \ 75 /* \ 76 * spin lock/unlock provide the needed smp_mb() before/after \ 77 */ \ 78 atomic_ops_lock(__flags); \ 79 _prev_ = *_p_; \ 80 if (_prev_ == _o_) \ 81 *_p_ = _n_; \ 82 atomic_ops_unlock(__flags); \ 83 _prev_; \ 84 }) 85 86 #endif 87 88 /* 89 * xchg 90 */ 91 #ifdef CONFIG_ARC_HAS_LLSC 92 93 #define __arch_xchg(ptr, val) \ 94 ({ \ 95 __asm__ __volatile__( \ 96 " ex %0, [%1] \n" /* set new value */ \ 97 : "+r"(val) \ 98 : "r"(ptr) \ 99 : "memory"); \ 100 _val_; /* get old value */ \ 101 }) 102 103 #define arch_xchg_relaxed(ptr, val) \ 104 ({ \ 105 __typeof__(ptr) _p_ = (ptr); \ 106 __typeof__(*(ptr)) _val_ = (val); \ 107 \ 108 switch (sizeof(*(_p_))) { \ 109 case 4: \ 110 _val_ = __arch_xchg(_p_, _val_); \ 111 break; \ 112 default: \ 113 BUILD_BUG(); \ 114 } \ 115 _val_; \ 116 }) 117 118 #else /* !CONFIG_ARC_HAS_LLSC */ 119 120 /* 121 * EX instructions is baseline and present in !LLSC too. But in this 122 * regime it still needs use @atomic_ops_lock spinlock to allow interop 123 * with cmpxchg() which uses spinlock in !LLSC 124 * (llist.h use xchg and cmpxchg on sama data) 125 */ 126 127 #define arch_xchg(ptr, val) \ 128 ({ \ 129 __typeof__(ptr) _p_ = (ptr); \ 130 __typeof__(*(ptr)) _val_ = (val); \ 131 \ 132 unsigned long __flags; \ 133 \ 134 atomic_ops_lock(__flags); \ 135 \ 136 __asm__ __volatile__( \ 137 " ex %0, [%1] \n" \ 138 : "+r"(_val_) \ 139 : "r"(_p_) \ 140 : "memory"); \ 141 \ 142 atomic_ops_unlock(__flags); \ 143 _val_; \ 144 }) 145 146 #endif 147 148 #endif 149