at v2.6.15 316 lines 7.4 kB view raw
1#ifndef _ASM_M32R_ATOMIC_H 2#define _ASM_M32R_ATOMIC_H 3 4/* 5 * linux/include/asm-m32r/atomic.h 6 * 7 * M32R version: 8 * Copyright (C) 2001, 2002 Hitoshi Yamamoto 9 * Copyright (C) 2004 Hirokazu Takata <takata at linux-m32r.org> 10 */ 11 12#include <linux/config.h> 13#include <asm/assembler.h> 14#include <asm/system.h> 15 16/* 17 * Atomic operations that C can't guarantee us. Useful for 18 * resource counting etc.. 19 */ 20 21/* 22 * Make sure gcc doesn't try to be clever and move things around 23 * on us. We need to use _exactly_ the address the user gave us, 24 * not some alias that contains the same information. 25 */ 26typedef struct { volatile int counter; } atomic_t; 27 28#define ATOMIC_INIT(i) { (i) } 29 30/** 31 * atomic_read - read atomic variable 32 * @v: pointer of type atomic_t 33 * 34 * Atomically reads the value of @v. 35 */ 36#define atomic_read(v) ((v)->counter) 37 38/** 39 * atomic_set - set atomic variable 40 * @v: pointer of type atomic_t 41 * @i: required value 42 * 43 * Atomically sets the value of @v to @i. 44 */ 45#define atomic_set(v,i) (((v)->counter) = (i)) 46 47/** 48 * atomic_add_return - add integer to atomic variable and return it 49 * @i: integer value to add 50 * @v: pointer of type atomic_t 51 * 52 * Atomically adds @i to @v and return (@i + @v). 53 */ 54static __inline__ int atomic_add_return(int i, atomic_t *v) 55{ 56 unsigned long flags; 57 int result; 58 59 local_irq_save(flags); 60 __asm__ __volatile__ ( 61 "# atomic_add_return \n\t" 62 DCACHE_CLEAR("%0", "r4", "%1") 63 M32R_LOCK" %0, @%1; \n\t" 64 "add %0, %2; \n\t" 65 M32R_UNLOCK" %0, @%1; \n\t" 66 : "=&r" (result) 67 : "r" (&v->counter), "r" (i) 68 : "memory" 69#ifdef CONFIG_CHIP_M32700_TS1 70 , "r4" 71#endif /* CONFIG_CHIP_M32700_TS1 */ 72 ); 73 local_irq_restore(flags); 74 75 return result; 76} 77 78/** 79 * atomic_sub_return - subtract integer from atomic variable and return it 80 * @i: integer value to subtract 81 * @v: pointer of type atomic_t 82 * 83 * Atomically subtracts @i from @v and return (@v - @i). 84 */ 85static __inline__ int atomic_sub_return(int i, atomic_t *v) 86{ 87 unsigned long flags; 88 int result; 89 90 local_irq_save(flags); 91 __asm__ __volatile__ ( 92 "# atomic_sub_return \n\t" 93 DCACHE_CLEAR("%0", "r4", "%1") 94 M32R_LOCK" %0, @%1; \n\t" 95 "sub %0, %2; \n\t" 96 M32R_UNLOCK" %0, @%1; \n\t" 97 : "=&r" (result) 98 : "r" (&v->counter), "r" (i) 99 : "memory" 100#ifdef CONFIG_CHIP_M32700_TS1 101 , "r4" 102#endif /* CONFIG_CHIP_M32700_TS1 */ 103 ); 104 local_irq_restore(flags); 105 106 return result; 107} 108 109/** 110 * atomic_add - add integer to atomic variable 111 * @i: integer value to add 112 * @v: pointer of type atomic_t 113 * 114 * Atomically adds @i to @v. 115 */ 116#define atomic_add(i,v) ((void) atomic_add_return((i), (v))) 117 118/** 119 * atomic_sub - subtract the atomic variable 120 * @i: integer value to subtract 121 * @v: pointer of type atomic_t 122 * 123 * Atomically subtracts @i from @v. 124 */ 125#define atomic_sub(i,v) ((void) atomic_sub_return((i), (v))) 126 127/** 128 * atomic_sub_and_test - subtract value from variable and test result 129 * @i: integer value to subtract 130 * @v: pointer of type atomic_t 131 * 132 * Atomically subtracts @i from @v and returns 133 * true if the result is zero, or false for all 134 * other cases. 135 */ 136#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0) 137 138/** 139 * atomic_inc_return - increment atomic variable and return it 140 * @v: pointer of type atomic_t 141 * 142 * Atomically increments @v by 1 and returns the result. 143 */ 144static __inline__ int atomic_inc_return(atomic_t *v) 145{ 146 unsigned long flags; 147 int result; 148 149 local_irq_save(flags); 150 __asm__ __volatile__ ( 151 "# atomic_inc_return \n\t" 152 DCACHE_CLEAR("%0", "r4", "%1") 153 M32R_LOCK" %0, @%1; \n\t" 154 "addi %0, #1; \n\t" 155 M32R_UNLOCK" %0, @%1; \n\t" 156 : "=&r" (result) 157 : "r" (&v->counter) 158 : "memory" 159#ifdef CONFIG_CHIP_M32700_TS1 160 , "r4" 161#endif /* CONFIG_CHIP_M32700_TS1 */ 162 ); 163 local_irq_restore(flags); 164 165 return result; 166} 167 168/** 169 * atomic_dec_return - decrement atomic variable and return it 170 * @v: pointer of type atomic_t 171 * 172 * Atomically decrements @v by 1 and returns the result. 173 */ 174static __inline__ int atomic_dec_return(atomic_t *v) 175{ 176 unsigned long flags; 177 int result; 178 179 local_irq_save(flags); 180 __asm__ __volatile__ ( 181 "# atomic_dec_return \n\t" 182 DCACHE_CLEAR("%0", "r4", "%1") 183 M32R_LOCK" %0, @%1; \n\t" 184 "addi %0, #-1; \n\t" 185 M32R_UNLOCK" %0, @%1; \n\t" 186 : "=&r" (result) 187 : "r" (&v->counter) 188 : "memory" 189#ifdef CONFIG_CHIP_M32700_TS1 190 , "r4" 191#endif /* CONFIG_CHIP_M32700_TS1 */ 192 ); 193 local_irq_restore(flags); 194 195 return result; 196} 197 198/** 199 * atomic_inc - increment atomic variable 200 * @v: pointer of type atomic_t 201 * 202 * Atomically increments @v by 1. 203 */ 204#define atomic_inc(v) ((void)atomic_inc_return(v)) 205 206/** 207 * atomic_dec - decrement atomic variable 208 * @v: pointer of type atomic_t 209 * 210 * Atomically decrements @v by 1. 211 */ 212#define atomic_dec(v) ((void)atomic_dec_return(v)) 213 214/** 215 * atomic_inc_and_test - increment and test 216 * @v: pointer of type atomic_t 217 * 218 * Atomically increments @v by 1 219 * and returns true if the result is zero, or false for all 220 * other cases. 221 */ 222#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) 223 224/** 225 * atomic_dec_and_test - decrement and test 226 * @v: pointer of type atomic_t 227 * 228 * Atomically decrements @v by 1 and 229 * returns true if the result is 0, or false for all 230 * other cases. 231 */ 232#define atomic_dec_and_test(v) (atomic_dec_return(v) == 0) 233 234/** 235 * atomic_add_negative - add and test if negative 236 * @v: pointer of type atomic_t 237 * @i: integer value to add 238 * 239 * Atomically adds @i to @v and returns true 240 * if the result is negative, or false when 241 * result is greater than or equal to zero. 242 */ 243#define atomic_add_negative(i,v) (atomic_add_return((i), (v)) < 0) 244 245#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n))) 246 247/** 248 * atomic_add_unless - add unless the number is a given value 249 * @v: pointer of type atomic_t 250 * @a: the amount to add to v... 251 * @u: ...unless v is equal to u. 252 * 253 * Atomically adds @a to @v, so long as it was not @u. 254 * Returns non-zero if @v was not @u, and zero otherwise. 255 */ 256#define atomic_add_unless(v, a, u) \ 257({ \ 258 int c, old; \ 259 c = atomic_read(v); \ 260 while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \ 261 c = old; \ 262 c != (u); \ 263}) 264#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) 265 266static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *addr) 267{ 268 unsigned long flags; 269 unsigned long tmp; 270 271 local_irq_save(flags); 272 __asm__ __volatile__ ( 273 "# atomic_clear_mask \n\t" 274 DCACHE_CLEAR("%0", "r5", "%1") 275 M32R_LOCK" %0, @%1; \n\t" 276 "and %0, %2; \n\t" 277 M32R_UNLOCK" %0, @%1; \n\t" 278 : "=&r" (tmp) 279 : "r" (addr), "r" (~mask) 280 : "memory" 281#ifdef CONFIG_CHIP_M32700_TS1 282 , "r5" 283#endif /* CONFIG_CHIP_M32700_TS1 */ 284 ); 285 local_irq_restore(flags); 286} 287 288static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *addr) 289{ 290 unsigned long flags; 291 unsigned long tmp; 292 293 local_irq_save(flags); 294 __asm__ __volatile__ ( 295 "# atomic_set_mask \n\t" 296 DCACHE_CLEAR("%0", "r5", "%1") 297 M32R_LOCK" %0, @%1; \n\t" 298 "or %0, %2; \n\t" 299 M32R_UNLOCK" %0, @%1; \n\t" 300 : "=&r" (tmp) 301 : "r" (addr), "r" (mask) 302 : "memory" 303#ifdef CONFIG_CHIP_M32700_TS1 304 , "r5" 305#endif /* CONFIG_CHIP_M32700_TS1 */ 306 ); 307 local_irq_restore(flags); 308} 309 310/* Atomic operations are already serializing on m32r */ 311#define smp_mb__before_atomic_dec() barrier() 312#define smp_mb__after_atomic_dec() barrier() 313#define smp_mb__before_atomic_inc() barrier() 314#define smp_mb__after_atomic_inc() barrier() 315 316#endif /* _ASM_M32R_ATOMIC_H */