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

csky: Atomic operations

This patch adds atomic, cmpxchg, spinlock files.

Signed-off-by: Guo Ren <ren_guo@c-sky.com>
Cc: Andrea Parri <andrea.parri@amarulasolutions.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Peter Zijlstra <peterz@infradead.org>

Guo Ren a0ae6280 e38a5272

+665
+212
arch/csky/include/asm/atomic.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #ifndef __ASM_CSKY_ATOMIC_H 4 + #define __ASM_CSKY_ATOMIC_H 5 + 6 + #include <linux/version.h> 7 + #include <asm/cmpxchg.h> 8 + #include <asm/barrier.h> 9 + 10 + #ifdef CONFIG_CPU_HAS_LDSTEX 11 + 12 + #define __atomic_add_unless __atomic_add_unless 13 + static inline int __atomic_add_unless(atomic_t *v, int a, int u) 14 + { 15 + unsigned long tmp, ret; 16 + 17 + smp_mb(); 18 + 19 + asm volatile ( 20 + "1: ldex.w %0, (%3) \n" 21 + " mov %1, %0 \n" 22 + " cmpne %0, %4 \n" 23 + " bf 2f \n" 24 + " add %0, %2 \n" 25 + " stex.w %0, (%3) \n" 26 + " bez %0, 1b \n" 27 + "2: \n" 28 + : "=&r" (tmp), "=&r" (ret) 29 + : "r" (a), "r"(&v->counter), "r"(u) 30 + : "memory"); 31 + 32 + if (ret != u) 33 + smp_mb(); 34 + 35 + return ret; 36 + } 37 + 38 + #define ATOMIC_OP(op, c_op) \ 39 + static inline void atomic_##op(int i, atomic_t *v) \ 40 + { \ 41 + unsigned long tmp; \ 42 + \ 43 + asm volatile ( \ 44 + "1: ldex.w %0, (%2) \n" \ 45 + " " #op " %0, %1 \n" \ 46 + " stex.w %0, (%2) \n" \ 47 + " bez %0, 1b \n" \ 48 + : "=&r" (tmp) \ 49 + : "r" (i), "r"(&v->counter) \ 50 + : "memory"); \ 51 + } 52 + 53 + #define ATOMIC_OP_RETURN(op, c_op) \ 54 + static inline int atomic_##op##_return(int i, atomic_t *v) \ 55 + { \ 56 + unsigned long tmp, ret; \ 57 + \ 58 + smp_mb(); \ 59 + asm volatile ( \ 60 + "1: ldex.w %0, (%3) \n" \ 61 + " " #op " %0, %2 \n" \ 62 + " mov %1, %0 \n" \ 63 + " stex.w %0, (%3) \n" \ 64 + " bez %0, 1b \n" \ 65 + : "=&r" (tmp), "=&r" (ret) \ 66 + : "r" (i), "r"(&v->counter) \ 67 + : "memory"); \ 68 + smp_mb(); \ 69 + \ 70 + return ret; \ 71 + } 72 + 73 + #define ATOMIC_FETCH_OP(op, c_op) \ 74 + static inline int atomic_fetch_##op(int i, atomic_t *v) \ 75 + { \ 76 + unsigned long tmp, ret; \ 77 + \ 78 + smp_mb(); \ 79 + asm volatile ( \ 80 + "1: ldex.w %0, (%3) \n" \ 81 + " mov %1, %0 \n" \ 82 + " " #op " %0, %2 \n" \ 83 + " stex.w %0, (%3) \n" \ 84 + " bez %0, 1b \n" \ 85 + : "=&r" (tmp), "=&r" (ret) \ 86 + : "r" (i), "r"(&v->counter) \ 87 + : "memory"); \ 88 + smp_mb(); \ 89 + \ 90 + return ret; \ 91 + } 92 + 93 + #else /* CONFIG_CPU_HAS_LDSTEX */ 94 + 95 + #include <linux/irqflags.h> 96 + 97 + #define __atomic_add_unless __atomic_add_unless 98 + static inline int __atomic_add_unless(atomic_t *v, int a, int u) 99 + { 100 + unsigned long tmp, ret, flags; 101 + 102 + raw_local_irq_save(flags); 103 + 104 + asm volatile ( 105 + " ldw %0, (%3) \n" 106 + " mov %1, %0 \n" 107 + " cmpne %0, %4 \n" 108 + " bf 2f \n" 109 + " add %0, %2 \n" 110 + " stw %0, (%3) \n" 111 + "2: \n" 112 + : "=&r" (tmp), "=&r" (ret) 113 + : "r" (a), "r"(&v->counter), "r"(u) 114 + : "memory"); 115 + 116 + raw_local_irq_restore(flags); 117 + 118 + return ret; 119 + } 120 + 121 + #define ATOMIC_OP(op, c_op) \ 122 + static inline void atomic_##op(int i, atomic_t *v) \ 123 + { \ 124 + unsigned long tmp, flags; \ 125 + \ 126 + raw_local_irq_save(flags); \ 127 + \ 128 + asm volatile ( \ 129 + " ldw %0, (%2) \n" \ 130 + " " #op " %0, %1 \n" \ 131 + " stw %0, (%2) \n" \ 132 + : "=&r" (tmp) \ 133 + : "r" (i), "r"(&v->counter) \ 134 + : "memory"); \ 135 + \ 136 + raw_local_irq_restore(flags); \ 137 + } 138 + 139 + #define ATOMIC_OP_RETURN(op, c_op) \ 140 + static inline int atomic_##op##_return(int i, atomic_t *v) \ 141 + { \ 142 + unsigned long tmp, ret, flags; \ 143 + \ 144 + raw_local_irq_save(flags); \ 145 + \ 146 + asm volatile ( \ 147 + " ldw %0, (%3) \n" \ 148 + " " #op " %0, %2 \n" \ 149 + " stw %0, (%3) \n" \ 150 + " mov %1, %0 \n" \ 151 + : "=&r" (tmp), "=&r" (ret) \ 152 + : "r" (i), "r"(&v->counter) \ 153 + : "memory"); \ 154 + \ 155 + raw_local_irq_restore(flags); \ 156 + \ 157 + return ret; \ 158 + } 159 + 160 + #define ATOMIC_FETCH_OP(op, c_op) \ 161 + static inline int atomic_fetch_##op(int i, atomic_t *v) \ 162 + { \ 163 + unsigned long tmp, ret, flags; \ 164 + \ 165 + raw_local_irq_save(flags); \ 166 + \ 167 + asm volatile ( \ 168 + " ldw %0, (%3) \n" \ 169 + " mov %1, %0 \n" \ 170 + " " #op " %0, %2 \n" \ 171 + " stw %0, (%3) \n" \ 172 + : "=&r" (tmp), "=&r" (ret) \ 173 + : "r" (i), "r"(&v->counter) \ 174 + : "memory"); \ 175 + \ 176 + raw_local_irq_restore(flags); \ 177 + \ 178 + return ret; \ 179 + } 180 + 181 + #endif /* CONFIG_CPU_HAS_LDSTEX */ 182 + 183 + #define atomic_add_return atomic_add_return 184 + ATOMIC_OP_RETURN(add, +) 185 + #define atomic_sub_return atomic_sub_return 186 + ATOMIC_OP_RETURN(sub, -) 187 + 188 + #define atomic_fetch_add atomic_fetch_add 189 + ATOMIC_FETCH_OP(add, +) 190 + #define atomic_fetch_sub atomic_fetch_sub 191 + ATOMIC_FETCH_OP(sub, -) 192 + #define atomic_fetch_and atomic_fetch_and 193 + ATOMIC_FETCH_OP(and, &) 194 + #define atomic_fetch_or atomic_fetch_or 195 + ATOMIC_FETCH_OP(or, |) 196 + #define atomic_fetch_xor atomic_fetch_xor 197 + ATOMIC_FETCH_OP(xor, ^) 198 + 199 + #define atomic_and atomic_and 200 + ATOMIC_OP(and, &) 201 + #define atomic_or atomic_or 202 + ATOMIC_OP(or, |) 203 + #define atomic_xor atomic_xor 204 + ATOMIC_OP(xor, ^) 205 + 206 + #undef ATOMIC_FETCH_OP 207 + #undef ATOMIC_OP_RETURN 208 + #undef ATOMIC_OP 209 + 210 + #include <asm-generic/atomic.h> 211 + 212 + #endif /* __ASM_CSKY_ATOMIC_H */
+73
arch/csky/include/asm/cmpxchg.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #ifndef __ASM_CSKY_CMPXCHG_H 4 + #define __ASM_CSKY_CMPXCHG_H 5 + 6 + #ifdef CONFIG_CPU_HAS_LDSTEX 7 + #include <asm/barrier.h> 8 + 9 + extern void __bad_xchg(void); 10 + 11 + #define __xchg(new, ptr, size) \ 12 + ({ \ 13 + __typeof__(ptr) __ptr = (ptr); \ 14 + __typeof__(new) __new = (new); \ 15 + __typeof__(*(ptr)) __ret; \ 16 + unsigned long tmp; \ 17 + switch (size) { \ 18 + case 4: \ 19 + smp_mb(); \ 20 + asm volatile ( \ 21 + "1: ldex.w %0, (%3) \n" \ 22 + " mov %1, %2 \n" \ 23 + " stex.w %1, (%3) \n" \ 24 + " bez %1, 1b \n" \ 25 + : "=&r" (__ret), "=&r" (tmp) \ 26 + : "r" (__new), "r"(__ptr) \ 27 + :); \ 28 + smp_mb(); \ 29 + break; \ 30 + default: \ 31 + __bad_xchg(); \ 32 + } \ 33 + __ret; \ 34 + }) 35 + 36 + #define xchg(ptr, x) (__xchg((x), (ptr), sizeof(*(ptr)))) 37 + 38 + #define __cmpxchg(ptr, old, new, size) \ 39 + ({ \ 40 + __typeof__(ptr) __ptr = (ptr); \ 41 + __typeof__(new) __new = (new); \ 42 + __typeof__(new) __tmp; \ 43 + __typeof__(old) __old = (old); \ 44 + __typeof__(*(ptr)) __ret; \ 45 + switch (size) { \ 46 + case 4: \ 47 + smp_mb(); \ 48 + asm volatile ( \ 49 + "1: ldex.w %0, (%3) \n" \ 50 + " cmpne %0, %4 \n" \ 51 + " bt 2f \n" \ 52 + " mov %1, %2 \n" \ 53 + " stex.w %1, (%3) \n" \ 54 + " bez %1, 1b \n" \ 55 + "2: \n" \ 56 + : "=&r" (__ret), "=&r" (__tmp) \ 57 + : "r" (__new), "r"(__ptr), "r"(__old) \ 58 + :); \ 59 + smp_mb(); \ 60 + break; \ 61 + default: \ 62 + __bad_xchg(); \ 63 + } \ 64 + __ret; \ 65 + }) 66 + 67 + #define cmpxchg(ptr, o, n) \ 68 + (__cmpxchg((ptr), (o), (n), sizeof(*(ptr)))) 69 + #else 70 + #include <asm-generic/cmpxchg.h> 71 + #endif 72 + 73 + #endif /* __ASM_CSKY_CMPXCHG_H */
+256
arch/csky/include/asm/spinlock.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #ifndef __ASM_CSKY_SPINLOCK_H 4 + #define __ASM_CSKY_SPINLOCK_H 5 + 6 + #include <linux/spinlock_types.h> 7 + #include <asm/barrier.h> 8 + 9 + #ifdef CONFIG_QUEUED_RWLOCKS 10 + 11 + /* 12 + * Ticket-based spin-locking. 13 + */ 14 + static inline void arch_spin_lock(arch_spinlock_t *lock) 15 + { 16 + arch_spinlock_t lockval; 17 + u32 ticket_next = 1 << TICKET_NEXT; 18 + u32 *p = &lock->lock; 19 + u32 tmp; 20 + 21 + asm volatile ( 22 + "1: ldex.w %0, (%2) \n" 23 + " mov %1, %0 \n" 24 + " add %0, %3 \n" 25 + " stex.w %0, (%2) \n" 26 + " bez %0, 1b \n" 27 + : "=&r" (tmp), "=&r" (lockval) 28 + : "r"(p), "r"(ticket_next) 29 + : "cc"); 30 + 31 + while (lockval.tickets.next != lockval.tickets.owner) 32 + lockval.tickets.owner = READ_ONCE(lock->tickets.owner); 33 + 34 + smp_mb(); 35 + } 36 + 37 + static inline int arch_spin_trylock(arch_spinlock_t *lock) 38 + { 39 + u32 tmp, contended, res; 40 + u32 ticket_next = 1 << TICKET_NEXT; 41 + u32 *p = &lock->lock; 42 + 43 + do { 44 + asm volatile ( 45 + " ldex.w %0, (%3) \n" 46 + " movi %2, 1 \n" 47 + " rotli %1, %0, 16 \n" 48 + " cmpne %1, %0 \n" 49 + " bt 1f \n" 50 + " movi %2, 0 \n" 51 + " add %0, %0, %4 \n" 52 + " stex.w %0, (%3) \n" 53 + "1: \n" 54 + : "=&r" (res), "=&r" (tmp), "=&r" (contended) 55 + : "r"(p), "r"(ticket_next) 56 + : "cc"); 57 + } while (!res); 58 + 59 + if (!contended) 60 + smp_mb(); 61 + 62 + return !contended; 63 + } 64 + 65 + static inline void arch_spin_unlock(arch_spinlock_t *lock) 66 + { 67 + smp_mb(); 68 + WRITE_ONCE(lock->tickets.owner, lock->tickets.owner + 1); 69 + } 70 + 71 + static inline int arch_spin_value_unlocked(arch_spinlock_t lock) 72 + { 73 + return lock.tickets.owner == lock.tickets.next; 74 + } 75 + 76 + static inline int arch_spin_is_locked(arch_spinlock_t *lock) 77 + { 78 + return !arch_spin_value_unlocked(READ_ONCE(*lock)); 79 + } 80 + 81 + static inline int arch_spin_is_contended(arch_spinlock_t *lock) 82 + { 83 + struct __raw_tickets tickets = READ_ONCE(lock->tickets); 84 + 85 + return (tickets.next - tickets.owner) > 1; 86 + } 87 + #define arch_spin_is_contended arch_spin_is_contended 88 + 89 + #include <asm/qrwlock.h> 90 + 91 + /* See include/linux/spinlock.h */ 92 + #define smp_mb__after_spinlock() smp_mb() 93 + 94 + #else /* CONFIG_QUEUED_RWLOCKS */ 95 + 96 + /* 97 + * Test-and-set spin-locking. 98 + */ 99 + static inline void arch_spin_lock(arch_spinlock_t *lock) 100 + { 101 + u32 *p = &lock->lock; 102 + u32 tmp; 103 + 104 + asm volatile ( 105 + "1: ldex.w %0, (%1) \n" 106 + " bnez %0, 1b \n" 107 + " movi %0, 1 \n" 108 + " stex.w %0, (%1) \n" 109 + " bez %0, 1b \n" 110 + : "=&r" (tmp) 111 + : "r"(p) 112 + : "cc"); 113 + smp_mb(); 114 + } 115 + 116 + static inline void arch_spin_unlock(arch_spinlock_t *lock) 117 + { 118 + smp_mb(); 119 + WRITE_ONCE(lock->lock, 0); 120 + } 121 + 122 + static inline int arch_spin_trylock(arch_spinlock_t *lock) 123 + { 124 + u32 *p = &lock->lock; 125 + u32 tmp; 126 + 127 + asm volatile ( 128 + "1: ldex.w %0, (%1) \n" 129 + " bnez %0, 2f \n" 130 + " movi %0, 1 \n" 131 + " stex.w %0, (%1) \n" 132 + " bez %0, 1b \n" 133 + " movi %0, 0 \n" 134 + "2: \n" 135 + : "=&r" (tmp) 136 + : "r"(p) 137 + : "cc"); 138 + 139 + if (!tmp) 140 + smp_mb(); 141 + 142 + return !tmp; 143 + } 144 + 145 + #define arch_spin_is_locked(x) (READ_ONCE((x)->lock) != 0) 146 + 147 + /* 148 + * read lock/unlock/trylock 149 + */ 150 + static inline void arch_read_lock(arch_rwlock_t *lock) 151 + { 152 + u32 *p = &lock->lock; 153 + u32 tmp; 154 + 155 + asm volatile ( 156 + "1: ldex.w %0, (%1) \n" 157 + " blz %0, 1b \n" 158 + " addi %0, 1 \n" 159 + " stex.w %0, (%1) \n" 160 + " bez %0, 1b \n" 161 + : "=&r" (tmp) 162 + : "r"(p) 163 + : "cc"); 164 + smp_mb(); 165 + } 166 + 167 + static inline void arch_read_unlock(arch_rwlock_t *lock) 168 + { 169 + u32 *p = &lock->lock; 170 + u32 tmp; 171 + 172 + smp_mb(); 173 + asm volatile ( 174 + "1: ldex.w %0, (%1) \n" 175 + " subi %0, 1 \n" 176 + " stex.w %0, (%1) \n" 177 + " bez %0, 1b \n" 178 + : "=&r" (tmp) 179 + : "r"(p) 180 + : "cc"); 181 + } 182 + 183 + static inline int arch_read_trylock(arch_rwlock_t *lock) 184 + { 185 + u32 *p = &lock->lock; 186 + u32 tmp; 187 + 188 + asm volatile ( 189 + "1: ldex.w %0, (%1) \n" 190 + " blz %0, 2f \n" 191 + " addi %0, 1 \n" 192 + " stex.w %0, (%1) \n" 193 + " bez %0, 1b \n" 194 + " movi %0, 0 \n" 195 + "2: \n" 196 + : "=&r" (tmp) 197 + : "r"(p) 198 + : "cc"); 199 + 200 + if (!tmp) 201 + smp_mb(); 202 + 203 + return !tmp; 204 + } 205 + 206 + /* 207 + * write lock/unlock/trylock 208 + */ 209 + static inline void arch_write_lock(arch_rwlock_t *lock) 210 + { 211 + u32 *p = &lock->lock; 212 + u32 tmp; 213 + 214 + asm volatile ( 215 + "1: ldex.w %0, (%1) \n" 216 + " bnez %0, 1b \n" 217 + " subi %0, 1 \n" 218 + " stex.w %0, (%1) \n" 219 + " bez %0, 1b \n" 220 + : "=&r" (tmp) 221 + : "r"(p) 222 + : "cc"); 223 + smp_mb(); 224 + } 225 + 226 + static inline void arch_write_unlock(arch_rwlock_t *lock) 227 + { 228 + smp_mb(); 229 + WRITE_ONCE(lock->lock, 0); 230 + } 231 + 232 + static inline int arch_write_trylock(arch_rwlock_t *lock) 233 + { 234 + u32 *p = &lock->lock; 235 + u32 tmp; 236 + 237 + asm volatile ( 238 + "1: ldex.w %0, (%1) \n" 239 + " bnez %0, 2f \n" 240 + " subi %0, 1 \n" 241 + " stex.w %0, (%1) \n" 242 + " bez %0, 1b \n" 243 + " movi %0, 0 \n" 244 + "2: \n" 245 + : "=&r" (tmp) 246 + : "r"(p) 247 + : "cc"); 248 + 249 + if (!tmp) 250 + smp_mb(); 251 + 252 + return !tmp; 253 + } 254 + 255 + #endif /* CONFIG_QUEUED_RWLOCKS */ 256 + #endif /* __ASM_CSKY_SPINLOCK_H */
+37
arch/csky/include/asm/spinlock_types.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #ifndef __ASM_CSKY_SPINLOCK_TYPES_H 4 + #define __ASM_CSKY_SPINLOCK_TYPES_H 5 + 6 + #ifndef __LINUX_SPINLOCK_TYPES_H 7 + # error "please don't include this file directly" 8 + #endif 9 + 10 + #define TICKET_NEXT 16 11 + 12 + typedef struct { 13 + union { 14 + u32 lock; 15 + struct __raw_tickets { 16 + /* little endian */ 17 + u16 owner; 18 + u16 next; 19 + } tickets; 20 + }; 21 + } arch_spinlock_t; 22 + 23 + #define __ARCH_SPIN_LOCK_UNLOCKED { { 0 } } 24 + 25 + #ifdef CONFIG_QUEUED_RWLOCKS 26 + #include <asm-generic/qrwlock_types.h> 27 + 28 + #else /* CONFIG_NR_CPUS > 2 */ 29 + 30 + typedef struct { 31 + u32 lock; 32 + } arch_rwlock_t; 33 + 34 + #define __ARCH_RW_LOCK_UNLOCKED { 0 } 35 + 36 + #endif /* CONFIG_QUEUED_RWLOCKS */ 37 + #endif /* __ASM_CSKY_SPINLOCK_TYPES_H */
+87
arch/csky/kernel/atomic.S
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. 3 + 4 + #include <linux/linkage.h> 5 + #include <abi/entry.h> 6 + 7 + .text 8 + 9 + /* 10 + * int csky_cmpxchg(int oldval, int newval, int *ptr) 11 + * 12 + * If *ptr != oldval && return 1, 13 + * else *ptr = newval return 0. 14 + */ 15 + #ifdef CONFIG_CPU_HAS_LDSTEX 16 + ENTRY(csky_cmpxchg) 17 + USPTOKSP 18 + mfcr a3, epc 19 + INCTRAP a3 20 + 21 + subi sp, 8 22 + stw a3, (sp, 0) 23 + mfcr a3, epsr 24 + stw a3, (sp, 4) 25 + 26 + psrset ee 27 + 1: 28 + ldex a3, (a2) 29 + cmpne a0, a3 30 + bt16 2f 31 + mov a3, a1 32 + stex a3, (a2) 33 + bez a3, 1b 34 + 2: 35 + sync.is 36 + mvc a0 37 + ldw a3, (sp, 0) 38 + mtcr a3, epc 39 + ldw a3, (sp, 4) 40 + mtcr a3, epsr 41 + addi sp, 8 42 + KSPTOUSP 43 + rte 44 + END(csky_cmpxchg) 45 + #else 46 + ENTRY(csky_cmpxchg) 47 + USPTOKSP 48 + mfcr a3, epc 49 + INCTRAP a3 50 + 51 + subi sp, 8 52 + stw a3, (sp, 0) 53 + mfcr a3, epsr 54 + stw a3, (sp, 4) 55 + 56 + psrset ee 57 + 1: 58 + ldw a3, (a2) 59 + cmpne a0, a3 60 + bt16 3f 61 + 2: 62 + stw a1, (a2) 63 + 3: 64 + mvc a0 65 + ldw a3, (sp, 0) 66 + mtcr a3, epc 67 + ldw a3, (sp, 4) 68 + mtcr a3, epsr 69 + addi sp, 8 70 + KSPTOUSP 71 + rte 72 + END(csky_cmpxchg) 73 + 74 + /* 75 + * Called from tlbmodified exception 76 + */ 77 + ENTRY(csky_cmpxchg_fixup) 78 + mfcr a0, epc 79 + lrw a1, 2b 80 + cmpne a1, a0 81 + bt 1f 82 + subi a1, (2b - 1b) 83 + stw a1, (sp, LSAVE_PC) 84 + 1: 85 + rts 86 + END(csky_cmpxchg_fixup) 87 + #endif