at v2.6.22 201 lines 5.1 kB view raw
1/* 2 * Atomic operations that C can't guarantee us. Useful for 3 * resource counting etc. 4 * 5 * But use these as seldom as possible since they are slower than 6 * regular operations. 7 * 8 * Copyright (C) 2004-2006 Atmel Corporation 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 */ 14#ifndef __ASM_AVR32_ATOMIC_H 15#define __ASM_AVR32_ATOMIC_H 16 17#include <asm/system.h> 18 19typedef struct { volatile int counter; } atomic_t; 20#define ATOMIC_INIT(i) { (i) } 21 22#define atomic_read(v) ((v)->counter) 23#define atomic_set(v, i) (((v)->counter) = i) 24 25/* 26 * atomic_sub_return - subtract the atomic variable 27 * @i: integer value to subtract 28 * @v: pointer of type atomic_t 29 * 30 * Atomically subtracts @i from @v. Returns the resulting value. 31 */ 32static inline int atomic_sub_return(int i, atomic_t *v) 33{ 34 int result; 35 36 asm volatile( 37 "/* atomic_sub_return */\n" 38 "1: ssrf 5\n" 39 " ld.w %0, %2\n" 40 " sub %0, %3\n" 41 " stcond %1, %0\n" 42 " brne 1b" 43 : "=&r"(result), "=o"(v->counter) 44 : "m"(v->counter), "rKs21"(i) 45 : "cc"); 46 47 return result; 48} 49 50/* 51 * atomic_add_return - add integer to atomic variable 52 * @i: integer value to add 53 * @v: pointer of type atomic_t 54 * 55 * Atomically adds @i to @v. Returns the resulting value. 56 */ 57static inline int atomic_add_return(int i, atomic_t *v) 58{ 59 int result; 60 61 if (__builtin_constant_p(i) && (i >= -1048575) && (i <= 1048576)) 62 result = atomic_sub_return(-i, v); 63 else 64 asm volatile( 65 "/* atomic_add_return */\n" 66 "1: ssrf 5\n" 67 " ld.w %0, %1\n" 68 " add %0, %3\n" 69 " stcond %2, %0\n" 70 " brne 1b" 71 : "=&r"(result), "=o"(v->counter) 72 : "m"(v->counter), "r"(i) 73 : "cc", "memory"); 74 75 return result; 76} 77 78/* 79 * atomic_sub_unless - sub unless the number is a given value 80 * @v: pointer of type atomic_t 81 * @a: the amount to add to v... 82 * @u: ...unless v is equal to u. 83 * 84 * If the atomic value v is not equal to u, this function subtracts a 85 * from v, and returns non zero. If v is equal to u then it returns 86 * zero. This is done as an atomic operation. 87*/ 88static inline int atomic_sub_unless(atomic_t *v, int a, int u) 89{ 90 int tmp, result = 0; 91 92 asm volatile( 93 "/* atomic_sub_unless */\n" 94 "1: ssrf 5\n" 95 " ld.w %0, %3\n" 96 " cp.w %0, %5\n" 97 " breq 1f\n" 98 " sub %0, %4\n" 99 " stcond %2, %0\n" 100 " brne 1b\n" 101 " mov %1, 1\n" 102 "1:" 103 : "=&r"(tmp), "=&r"(result), "=o"(v->counter) 104 : "m"(v->counter), "rKs21"(a), "rKs21"(u) 105 : "cc", "memory"); 106 107 return result; 108} 109 110/* 111 * atomic_add_unless - add unless the number is a given value 112 * @v: pointer of type atomic_t 113 * @a: the amount to add to v... 114 * @u: ...unless v is equal to u. 115 * 116 * If the atomic value v is not equal to u, this function adds a to v, 117 * and returns non zero. If v is equal to u then it returns zero. This 118 * is done as an atomic operation. 119*/ 120static inline int atomic_add_unless(atomic_t *v, int a, int u) 121{ 122 int tmp, result; 123 124 if (__builtin_constant_p(a) && (a >= -1048575) && (a <= 1048576)) 125 result = atomic_sub_unless(v, -a, u); 126 else { 127 result = 0; 128 asm volatile( 129 "/* atomic_add_unless */\n" 130 "1: ssrf 5\n" 131 " ld.w %0, %3\n" 132 " cp.w %0, %5\n" 133 " breq 1f\n" 134 " add %0, %4\n" 135 " stcond %2, %0\n" 136 " brne 1b\n" 137 " mov %1, 1\n" 138 "1:" 139 : "=&r"(tmp), "=&r"(result), "=o"(v->counter) 140 : "m"(v->counter), "r"(a), "ir"(u) 141 : "cc", "memory"); 142 } 143 144 return result; 145} 146 147/* 148 * atomic_sub_if_positive - conditionally subtract integer from atomic variable 149 * @i: integer value to subtract 150 * @v: pointer of type atomic_t 151 * 152 * Atomically test @v and subtract @i if @v is greater or equal than @i. 153 * The function returns the old value of @v minus @i. 154 */ 155static inline int atomic_sub_if_positive(int i, atomic_t *v) 156{ 157 int result; 158 159 asm volatile( 160 "/* atomic_sub_if_positive */\n" 161 "1: ssrf 5\n" 162 " ld.w %0, %2\n" 163 " sub %0, %3\n" 164 " brlt 1f\n" 165 " stcond %1, %0\n" 166 " brne 1b\n" 167 "1:" 168 : "=&r"(result), "=o"(v->counter) 169 : "m"(v->counter), "ir"(i) 170 : "cc", "memory"); 171 172 return result; 173} 174 175#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) 176#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n))) 177 178#define atomic_sub(i, v) (void)atomic_sub_return(i, v) 179#define atomic_add(i, v) (void)atomic_add_return(i, v) 180#define atomic_dec(v) atomic_sub(1, (v)) 181#define atomic_inc(v) atomic_add(1, (v)) 182 183#define atomic_dec_return(v) atomic_sub_return(1, v) 184#define atomic_inc_return(v) atomic_add_return(1, v) 185 186#define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0) 187#define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0) 188#define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0) 189#define atomic_add_negative(i, v) (atomic_add_return(i, v) < 0) 190 191#define atomic_inc_not_zero(v) atomic_add_unless(v, 1, 0) 192#define atomic_dec_if_positive(v) atomic_sub_if_positive(1, v) 193 194#define smp_mb__before_atomic_dec() barrier() 195#define smp_mb__after_atomic_dec() barrier() 196#define smp_mb__before_atomic_inc() barrier() 197#define smp_mb__after_atomic_inc() barrier() 198 199#include <asm-generic/atomic.h> 200 201#endif /* __ASM_AVR32_ATOMIC_H */