at v3.2 348 lines 8.1 kB view raw
1/* MN10300 Atomic counter operations 2 * 3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 4 * Written by David Howells (dhowells@redhat.com) 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public Licence 8 * as published by the Free Software Foundation; either version 9 * 2 of the Licence, or (at your option) any later version. 10 */ 11#ifndef _ASM_ATOMIC_H 12#define _ASM_ATOMIC_H 13 14#include <asm/irqflags.h> 15 16#ifndef __ASSEMBLY__ 17 18#ifdef CONFIG_SMP 19#ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT 20static inline 21unsigned long __xchg(volatile unsigned long *m, unsigned long val) 22{ 23 unsigned long status; 24 unsigned long oldval; 25 26 asm volatile( 27 "1: mov %4,(_AAR,%3) \n" 28 " mov (_ADR,%3),%1 \n" 29 " mov %5,(_ADR,%3) \n" 30 " mov (_ADR,%3),%0 \n" /* flush */ 31 " mov (_ASR,%3),%0 \n" 32 " or %0,%0 \n" 33 " bne 1b \n" 34 : "=&r"(status), "=&r"(oldval), "=m"(*m) 35 : "a"(ATOMIC_OPS_BASE_ADDR), "r"(m), "r"(val) 36 : "memory", "cc"); 37 38 return oldval; 39} 40 41static inline unsigned long __cmpxchg(volatile unsigned long *m, 42 unsigned long old, unsigned long new) 43{ 44 unsigned long status; 45 unsigned long oldval; 46 47 asm volatile( 48 "1: mov %4,(_AAR,%3) \n" 49 " mov (_ADR,%3),%1 \n" 50 " cmp %5,%1 \n" 51 " bne 2f \n" 52 " mov %6,(_ADR,%3) \n" 53 "2: mov (_ADR,%3),%0 \n" /* flush */ 54 " mov (_ASR,%3),%0 \n" 55 " or %0,%0 \n" 56 " bne 1b \n" 57 : "=&r"(status), "=&r"(oldval), "=m"(*m) 58 : "a"(ATOMIC_OPS_BASE_ADDR), "r"(m), 59 "r"(old), "r"(new) 60 : "memory", "cc"); 61 62 return oldval; 63} 64#else /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */ 65#error "No SMP atomic operation support!" 66#endif /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */ 67 68#else /* CONFIG_SMP */ 69 70/* 71 * Emulate xchg for non-SMP MN10300 72 */ 73struct __xchg_dummy { unsigned long a[100]; }; 74#define __xg(x) ((struct __xchg_dummy *)(x)) 75 76static inline 77unsigned long __xchg(volatile unsigned long *m, unsigned long val) 78{ 79 unsigned long oldval; 80 unsigned long flags; 81 82 flags = arch_local_cli_save(); 83 oldval = *m; 84 *m = val; 85 arch_local_irq_restore(flags); 86 return oldval; 87} 88 89/* 90 * Emulate cmpxchg for non-SMP MN10300 91 */ 92static inline unsigned long __cmpxchg(volatile unsigned long *m, 93 unsigned long old, unsigned long new) 94{ 95 unsigned long oldval; 96 unsigned long flags; 97 98 flags = arch_local_cli_save(); 99 oldval = *m; 100 if (oldval == old) 101 *m = new; 102 arch_local_irq_restore(flags); 103 return oldval; 104} 105 106#endif /* CONFIG_SMP */ 107 108#define xchg(ptr, v) \ 109 ((__typeof__(*(ptr))) __xchg((unsigned long *)(ptr), \ 110 (unsigned long)(v))) 111 112#define cmpxchg(ptr, o, n) \ 113 ((__typeof__(*(ptr))) __cmpxchg((unsigned long *)(ptr), \ 114 (unsigned long)(o), \ 115 (unsigned long)(n))) 116 117#define atomic_xchg(ptr, v) (xchg(&(ptr)->counter, (v))) 118#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new))) 119 120#endif /* !__ASSEMBLY__ */ 121 122#ifndef CONFIG_SMP 123#include <asm-generic/atomic.h> 124#else 125 126/* 127 * Atomic operations that C can't guarantee us. Useful for 128 * resource counting etc.. 129 */ 130 131#define ATOMIC_INIT(i) { (i) } 132 133#ifdef __KERNEL__ 134 135/** 136 * atomic_read - read atomic variable 137 * @v: pointer of type atomic_t 138 * 139 * Atomically reads the value of @v. Note that the guaranteed 140 * useful range of an atomic_t is only 24 bits. 141 */ 142#define atomic_read(v) (ACCESS_ONCE((v)->counter)) 143 144/** 145 * atomic_set - set atomic variable 146 * @v: pointer of type atomic_t 147 * @i: required value 148 * 149 * Atomically sets the value of @v to @i. Note that the guaranteed 150 * useful range of an atomic_t is only 24 bits. 151 */ 152#define atomic_set(v, i) (((v)->counter) = (i)) 153 154/** 155 * atomic_add_return - add integer to atomic variable 156 * @i: integer value to add 157 * @v: pointer of type atomic_t 158 * 159 * Atomically adds @i to @v and returns the result 160 * Note that the guaranteed useful range of an atomic_t is only 24 bits. 161 */ 162static inline int atomic_add_return(int i, atomic_t *v) 163{ 164 int retval; 165#ifdef CONFIG_SMP 166 int status; 167 168 asm volatile( 169 "1: mov %4,(_AAR,%3) \n" 170 " mov (_ADR,%3),%1 \n" 171 " add %5,%1 \n" 172 " mov %1,(_ADR,%3) \n" 173 " mov (_ADR,%3),%0 \n" /* flush */ 174 " mov (_ASR,%3),%0 \n" 175 " or %0,%0 \n" 176 " bne 1b \n" 177 : "=&r"(status), "=&r"(retval), "=m"(v->counter) 178 : "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i) 179 : "memory", "cc"); 180 181#else 182 unsigned long flags; 183 184 flags = arch_local_cli_save(); 185 retval = v->counter; 186 retval += i; 187 v->counter = retval; 188 arch_local_irq_restore(flags); 189#endif 190 return retval; 191} 192 193/** 194 * atomic_sub_return - subtract integer from atomic variable 195 * @i: integer value to subtract 196 * @v: pointer of type atomic_t 197 * 198 * Atomically subtracts @i from @v and returns the result 199 * Note that the guaranteed useful range of an atomic_t is only 24 bits. 200 */ 201static inline int atomic_sub_return(int i, atomic_t *v) 202{ 203 int retval; 204#ifdef CONFIG_SMP 205 int status; 206 207 asm volatile( 208 "1: mov %4,(_AAR,%3) \n" 209 " mov (_ADR,%3),%1 \n" 210 " sub %5,%1 \n" 211 " mov %1,(_ADR,%3) \n" 212 " mov (_ADR,%3),%0 \n" /* flush */ 213 " mov (_ASR,%3),%0 \n" 214 " or %0,%0 \n" 215 " bne 1b \n" 216 : "=&r"(status), "=&r"(retval), "=m"(v->counter) 217 : "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i) 218 : "memory", "cc"); 219 220#else 221 unsigned long flags; 222 flags = arch_local_cli_save(); 223 retval = v->counter; 224 retval -= i; 225 v->counter = retval; 226 arch_local_irq_restore(flags); 227#endif 228 return retval; 229} 230 231static inline int atomic_add_negative(int i, atomic_t *v) 232{ 233 return atomic_add_return(i, v) < 0; 234} 235 236static inline void atomic_add(int i, atomic_t *v) 237{ 238 atomic_add_return(i, v); 239} 240 241static inline void atomic_sub(int i, atomic_t *v) 242{ 243 atomic_sub_return(i, v); 244} 245 246static inline void atomic_inc(atomic_t *v) 247{ 248 atomic_add_return(1, v); 249} 250 251static inline void atomic_dec(atomic_t *v) 252{ 253 atomic_sub_return(1, v); 254} 255 256#define atomic_dec_return(v) atomic_sub_return(1, (v)) 257#define atomic_inc_return(v) atomic_add_return(1, (v)) 258 259#define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0) 260#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) 261#define atomic_inc_and_test(v) (atomic_add_return(1, (v)) == 0) 262 263#define __atomic_add_unless(v, a, u) \ 264({ \ 265 int c, old; \ 266 c = atomic_read(v); \ 267 while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \ 268 c = old; \ 269 c; \ 270}) 271 272 273/** 274 * atomic_clear_mask - Atomically clear bits in memory 275 * @mask: Mask of the bits to be cleared 276 * @v: pointer to word in memory 277 * 278 * Atomically clears the bits set in mask from the memory word specified. 279 */ 280static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr) 281{ 282#ifdef CONFIG_SMP 283 int status; 284 285 asm volatile( 286 "1: mov %3,(_AAR,%2) \n" 287 " mov (_ADR,%2),%0 \n" 288 " and %4,%0 \n" 289 " mov %0,(_ADR,%2) \n" 290 " mov (_ADR,%2),%0 \n" /* flush */ 291 " mov (_ASR,%2),%0 \n" 292 " or %0,%0 \n" 293 " bne 1b \n" 294 : "=&r"(status), "=m"(*addr) 295 : "a"(ATOMIC_OPS_BASE_ADDR), "r"(addr), "r"(~mask) 296 : "memory", "cc"); 297#else 298 unsigned long flags; 299 300 mask = ~mask; 301 flags = arch_local_cli_save(); 302 *addr &= mask; 303 arch_local_irq_restore(flags); 304#endif 305} 306 307/** 308 * atomic_set_mask - Atomically set bits in memory 309 * @mask: Mask of the bits to be set 310 * @v: pointer to word in memory 311 * 312 * Atomically sets the bits set in mask from the memory word specified. 313 */ 314static inline void atomic_set_mask(unsigned long mask, unsigned long *addr) 315{ 316#ifdef CONFIG_SMP 317 int status; 318 319 asm volatile( 320 "1: mov %3,(_AAR,%2) \n" 321 " mov (_ADR,%2),%0 \n" 322 " or %4,%0 \n" 323 " mov %0,(_ADR,%2) \n" 324 " mov (_ADR,%2),%0 \n" /* flush */ 325 " mov (_ASR,%2),%0 \n" 326 " or %0,%0 \n" 327 " bne 1b \n" 328 : "=&r"(status), "=m"(*addr) 329 : "a"(ATOMIC_OPS_BASE_ADDR), "r"(addr), "r"(mask) 330 : "memory", "cc"); 331#else 332 unsigned long flags; 333 334 flags = arch_local_cli_save(); 335 *addr |= mask; 336 arch_local_irq_restore(flags); 337#endif 338} 339 340/* Atomic operations are already serializing on MN10300??? */ 341#define smp_mb__before_atomic_dec() barrier() 342#define smp_mb__after_atomic_dec() barrier() 343#define smp_mb__before_atomic_inc() barrier() 344#define smp_mb__after_atomic_inc() barrier() 345 346#endif /* __KERNEL__ */ 347#endif /* CONFIG_SMP */ 348#endif /* _ASM_ATOMIC_H */