Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARC: [plat-eznps] Use dedicated atomic/bitops/cmpxchg

We need our own implementaions since we lack LLSC support.
Our extended ISA provided with optimized solution for all 32bit
operations we see in these three headers.
Signed-off-by: Noam Camus <noamc@ezchip.com>

authored by

Noam Camus and committed by
Vineet Gupta
a5a10d99 8bcf2c48

+205 -14
+80 -3
arch/arc/include/asm/atomic.h
··· 17 17 #include <asm/barrier.h> 18 18 #include <asm/smp.h> 19 19 20 + #ifndef CONFIG_ARC_PLAT_EZNPS 21 + 20 22 #define atomic_read(v) READ_ONCE((v)->counter) 21 23 22 24 #ifdef CONFIG_ARC_HAS_LLSC ··· 182 180 ATOMIC_OP(or, |=, or) 183 181 ATOMIC_OP(xor, ^=, xor) 184 182 185 - #undef ATOMIC_OPS 186 - #undef ATOMIC_OP_RETURN 187 - #undef ATOMIC_OP 188 183 #undef SCOND_FAIL_RETRY_VAR_DEF 189 184 #undef SCOND_FAIL_RETRY_ASM 190 185 #undef SCOND_FAIL_RETRY_VARS 186 + 187 + #else /* CONFIG_ARC_PLAT_EZNPS */ 188 + 189 + static inline int atomic_read(const atomic_t *v) 190 + { 191 + int temp; 192 + 193 + __asm__ __volatile__( 194 + " ld.di %0, [%1]" 195 + : "=r"(temp) 196 + : "r"(&v->counter) 197 + : "memory"); 198 + return temp; 199 + } 200 + 201 + static inline void atomic_set(atomic_t *v, int i) 202 + { 203 + __asm__ __volatile__( 204 + " st.di %0,[%1]" 205 + : 206 + : "r"(i), "r"(&v->counter) 207 + : "memory"); 208 + } 209 + 210 + #define ATOMIC_OP(op, c_op, asm_op) \ 211 + static inline void atomic_##op(int i, atomic_t *v) \ 212 + { \ 213 + __asm__ __volatile__( \ 214 + " mov r2, %0\n" \ 215 + " mov r3, %1\n" \ 216 + " .word %2\n" \ 217 + : \ 218 + : "r"(i), "r"(&v->counter), "i"(asm_op) \ 219 + : "r2", "r3", "memory"); \ 220 + } \ 221 + 222 + #define ATOMIC_OP_RETURN(op, c_op, asm_op) \ 223 + static inline int atomic_##op##_return(int i, atomic_t *v) \ 224 + { \ 225 + unsigned int temp = i; \ 226 + \ 227 + /* Explicit full memory barrier needed before/after */ \ 228 + smp_mb(); \ 229 + \ 230 + __asm__ __volatile__( \ 231 + " mov r2, %0\n" \ 232 + " mov r3, %1\n" \ 233 + " .word %2\n" \ 234 + " mov %0, r2" \ 235 + : "+r"(temp) \ 236 + : "r"(&v->counter), "i"(asm_op) \ 237 + : "r2", "r3", "memory"); \ 238 + \ 239 + smp_mb(); \ 240 + \ 241 + temp c_op i; \ 242 + \ 243 + return temp; \ 244 + } 245 + 246 + #define ATOMIC_OPS(op, c_op, asm_op) \ 247 + ATOMIC_OP(op, c_op, asm_op) \ 248 + ATOMIC_OP_RETURN(op, c_op, asm_op) 249 + 250 + ATOMIC_OPS(add, +=, CTOP_INST_AADD_DI_R2_R2_R3) 251 + #define atomic_sub(i, v) atomic_add(-(i), (v)) 252 + #define atomic_sub_return(i, v) atomic_add_return(-(i), (v)) 253 + 254 + ATOMIC_OP(and, &=, CTOP_INST_AAND_DI_R2_R2_R3) 255 + #define atomic_andnot(mask, v) atomic_and(~(mask), (v)) 256 + ATOMIC_OP(or, |=, CTOP_INST_AOR_DI_R2_R2_R3) 257 + ATOMIC_OP(xor, ^=, CTOP_INST_AXOR_DI_R2_R2_R3) 258 + 259 + #endif /* CONFIG_ARC_PLAT_EZNPS */ 260 + 261 + #undef ATOMIC_OPS 262 + #undef ATOMIC_OP_RETURN 263 + #undef ATOMIC_OP 191 264 192 265 /** 193 266 * __atomic_add_unless - add unless the number is a given value
+57 -3
arch/arc/include/asm/bitops.h
··· 22 22 #include <asm/smp.h> 23 23 #endif 24 24 25 - #if defined(CONFIG_ARC_HAS_LLSC) 25 + #ifdef CONFIG_ARC_HAS_LLSC 26 26 27 27 /* 28 28 * Hardware assisted Atomic-R-M-W ··· 88 88 return (old & (1 << nr)) != 0; \ 89 89 } 90 90 91 - #else /* !CONFIG_ARC_HAS_LLSC */ 91 + #elif !defined(CONFIG_ARC_PLAT_EZNPS) 92 92 93 93 /* 94 94 * Non hardware assisted Atomic-R-M-W ··· 139 139 return (old & (1UL << (nr & 0x1f))) != 0; \ 140 140 } 141 141 142 - #endif /* CONFIG_ARC_HAS_LLSC */ 142 + #else /* CONFIG_ARC_PLAT_EZNPS */ 143 + 144 + #define BIT_OP(op, c_op, asm_op) \ 145 + static inline void op##_bit(unsigned long nr, volatile unsigned long *m)\ 146 + { \ 147 + m += nr >> 5; \ 148 + \ 149 + nr = (1UL << (nr & 0x1f)); \ 150 + if (asm_op == CTOP_INST_AAND_DI_R2_R2_R3) \ 151 + nr = ~nr; \ 152 + \ 153 + __asm__ __volatile__( \ 154 + " mov r2, %0\n" \ 155 + " mov r3, %1\n" \ 156 + " .word %2\n" \ 157 + : \ 158 + : "r"(nr), "r"(m), "i"(asm_op) \ 159 + : "r2", "r3", "memory"); \ 160 + } 161 + 162 + #define TEST_N_BIT_OP(op, c_op, asm_op) \ 163 + static inline int test_and_##op##_bit(unsigned long nr, volatile unsigned long *m)\ 164 + { \ 165 + unsigned long old; \ 166 + \ 167 + m += nr >> 5; \ 168 + \ 169 + nr = old = (1UL << (nr & 0x1f)); \ 170 + if (asm_op == CTOP_INST_AAND_DI_R2_R2_R3) \ 171 + old = ~old; \ 172 + \ 173 + /* Explicit full memory barrier needed before/after */ \ 174 + smp_mb(); \ 175 + \ 176 + __asm__ __volatile__( \ 177 + " mov r2, %0\n" \ 178 + " mov r3, %1\n" \ 179 + " .word %2\n" \ 180 + " mov %0, r2" \ 181 + : "+r"(old) \ 182 + : "r"(m), "i"(asm_op) \ 183 + : "r2", "r3", "memory"); \ 184 + \ 185 + smp_mb(); \ 186 + \ 187 + return (old & nr) != 0; \ 188 + } 189 + 190 + #endif /* CONFIG_ARC_PLAT_EZNPS */ 143 191 144 192 /*************************************** 145 193 * Non atomic variants ··· 229 181 /* __test_and_set_bit(), __test_and_clear_bit(), __test_and_change_bit() */\ 230 182 __TEST_N_BIT_OP(op, c_op, asm_op) 231 183 184 + #ifndef CONFIG_ARC_PLAT_EZNPS 232 185 BIT_OPS(set, |, bset) 233 186 BIT_OPS(clear, & ~, bclr) 234 187 BIT_OPS(change, ^, bxor) 188 + #else 189 + BIT_OPS(set, |, CTOP_INST_AOR_DI_R2_R2_R3) 190 + BIT_OPS(clear, & ~, CTOP_INST_AAND_DI_R2_R2_R3) 191 + BIT_OPS(change, ^, CTOP_INST_AXOR_DI_R2_R2_R3) 192 + #endif 235 193 236 194 /* 237 195 * This routine doesn't need to be atomic.
+68 -8
arch/arc/include/asm/cmpxchg.h
··· 44 44 return prev; 45 45 } 46 46 47 - #else 47 + #elif !defined(CONFIG_ARC_PLAT_EZNPS) 48 48 49 49 static inline unsigned long 50 50 __cmpxchg(volatile void *ptr, unsigned long expected, unsigned long new) ··· 64 64 return prev; 65 65 } 66 66 67 + #else /* CONFIG_ARC_PLAT_EZNPS */ 68 + 69 + static inline unsigned long 70 + __cmpxchg(volatile void *ptr, unsigned long expected, unsigned long new) 71 + { 72 + /* 73 + * Explicit full memory barrier needed before/after 74 + */ 75 + smp_mb(); 76 + 77 + write_aux_reg(CTOP_AUX_GPA1, expected); 78 + 79 + __asm__ __volatile__( 80 + " mov r2, %0\n" 81 + " mov r3, %1\n" 82 + " .word %2\n" 83 + " mov %0, r2" 84 + : "+r"(new) 85 + : "r"(ptr), "i"(CTOP_INST_EXC_DI_R2_R2_R3) 86 + : "r2", "r3", "memory"); 87 + 88 + smp_mb(); 89 + 90 + return new; 91 + } 92 + 67 93 #endif /* CONFIG_ARC_HAS_LLSC */ 68 94 69 95 #define cmpxchg(ptr, o, n) ((typeof(*(ptr)))__cmpxchg((ptr), \ 70 96 (unsigned long)(o), (unsigned long)(n))) 71 97 72 98 /* 73 - * Since not supported natively, ARC cmpxchg() uses atomic_ops_lock (UP/SMP) 74 - * just to gaurantee semantics. 75 - * atomic_cmpxchg() needs to use the same locks as it's other atomic siblings 76 - * which also happens to be atomic_ops_lock. 77 - * 78 - * Thus despite semantically being different, implementation of atomic_cmpxchg() 79 - * is same as cmpxchg(). 99 + * atomic_cmpxchg is same as cmpxchg 100 + * LLSC: only different in data-type, semantics are exactly same 101 + * !LLSC: cmpxchg() has to use an external lock atomic_ops_lock to guarantee 102 + * semantics, and this lock also happens to be used by atomic_*() 80 103 */ 81 104 #define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n))) 82 105 106 + 107 + #ifndef CONFIG_ARC_PLAT_EZNPS 83 108 84 109 /* 85 110 * xchg (reg with memory) based on "Native atomic" EX insn ··· 167 142 #define xchg(ptr, with) _xchg(ptr, with) 168 143 169 144 #endif 145 + 146 + #else /* CONFIG_ARC_PLAT_EZNPS */ 147 + 148 + static inline unsigned long __xchg(unsigned long val, volatile void *ptr, 149 + int size) 150 + { 151 + extern unsigned long __xchg_bad_pointer(void); 152 + 153 + switch (size) { 154 + case 4: 155 + /* 156 + * Explicit full memory barrier needed before/after 157 + */ 158 + smp_mb(); 159 + 160 + __asm__ __volatile__( 161 + " mov r2, %0\n" 162 + " mov r3, %1\n" 163 + " .word %2\n" 164 + " mov %0, r2\n" 165 + : "+r"(val) 166 + : "r"(ptr), "i"(CTOP_INST_XEX_DI_R2_R2_R3) 167 + : "r2", "r3", "memory"); 168 + 169 + smp_mb(); 170 + 171 + return val; 172 + } 173 + return __xchg_bad_pointer(); 174 + } 175 + 176 + #define xchg(ptr, with) ((typeof(*(ptr)))__xchg((unsigned long)(with), (ptr), \ 177 + sizeof(*(ptr)))) 178 + 179 + #endif /* CONFIG_ARC_PLAT_EZNPS */ 170 180 171 181 /* 172 182 * "atomic" variant of xchg()