diff options
Diffstat (limited to 'arch/alpha/include/asm/atomic.h')
| -rw-r--r-- | arch/alpha/include/asm/atomic.h | 88 |
1 files changed, 65 insertions, 23 deletions
diff --git a/arch/alpha/include/asm/atomic.h b/arch/alpha/include/asm/atomic.h index c2cbe4fc391c..78b03ef39f6f 100644 --- a/arch/alpha/include/asm/atomic.h +++ b/arch/alpha/include/asm/atomic.h | |||
| @@ -186,17 +186,24 @@ static __inline__ long atomic64_sub_return(long i, atomic64_t * v) | |||
| 186 | */ | 186 | */ |
| 187 | static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) | 187 | static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) |
| 188 | { | 188 | { |
| 189 | int c, old; | 189 | int c, new, old; |
| 190 | c = atomic_read(v); | 190 | smp_mb(); |
| 191 | for (;;) { | 191 | __asm__ __volatile__( |
| 192 | if (unlikely(c == (u))) | 192 | "1: ldl_l %[old],%[mem]\n" |
| 193 | break; | 193 | " cmpeq %[old],%[u],%[c]\n" |
| 194 | old = atomic_cmpxchg((v), c, c + (a)); | 194 | " addl %[old],%[a],%[new]\n" |
| 195 | if (likely(old == c)) | 195 | " bne %[c],2f\n" |
| 196 | break; | 196 | " stl_c %[new],%[mem]\n" |
| 197 | c = old; | 197 | " beq %[new],3f\n" |
| 198 | } | 198 | "2:\n" |
| 199 | return c; | 199 | ".subsection 2\n" |
| 200 | "3: br 1b\n" | ||
| 201 | ".previous" | ||
| 202 | : [old] "=&r"(old), [new] "=&r"(new), [c] "=&r"(c) | ||
| 203 | : [mem] "m"(*v), [a] "rI"(a), [u] "rI"((long)u) | ||
| 204 | : "memory"); | ||
| 205 | smp_mb(); | ||
| 206 | return old; | ||
| 200 | } | 207 | } |
| 201 | 208 | ||
| 202 | 209 | ||
| @@ -207,21 +214,56 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) | |||
| 207 | * @u: ...unless v is equal to u. | 214 | * @u: ...unless v is equal to u. |
| 208 | * | 215 | * |
| 209 | * Atomically adds @a to @v, so long as it was not @u. | 216 | * Atomically adds @a to @v, so long as it was not @u. |
| 210 | * Returns the old value of @v. | 217 | * Returns true iff @v was not @u. |
| 211 | */ | 218 | */ |
| 212 | static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) | 219 | static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) |
| 213 | { | 220 | { |
| 214 | long c, old; | 221 | long c, tmp; |
| 215 | c = atomic64_read(v); | 222 | smp_mb(); |
| 216 | for (;;) { | 223 | __asm__ __volatile__( |
| 217 | if (unlikely(c == (u))) | 224 | "1: ldq_l %[tmp],%[mem]\n" |
| 218 | break; | 225 | " cmpeq %[tmp],%[u],%[c]\n" |
| 219 | old = atomic64_cmpxchg((v), c, c + (a)); | 226 | " addq %[tmp],%[a],%[tmp]\n" |
| 220 | if (likely(old == c)) | 227 | " bne %[c],2f\n" |
| 221 | break; | 228 | " stq_c %[tmp],%[mem]\n" |
| 222 | c = old; | 229 | " beq %[tmp],3f\n" |
| 223 | } | 230 | "2:\n" |
| 224 | return c != (u); | 231 | ".subsection 2\n" |
| 232 | "3: br 1b\n" | ||
| 233 | ".previous" | ||
| 234 | : [tmp] "=&r"(tmp), [c] "=&r"(c) | ||
| 235 | : [mem] "m"(*v), [a] "rI"(a), [u] "rI"(u) | ||
| 236 | : "memory"); | ||
| 237 | smp_mb(); | ||
| 238 | return !c; | ||
| 239 | } | ||
| 240 | |||
| 241 | /* | ||
| 242 | * atomic64_dec_if_positive - decrement by 1 if old value positive | ||
| 243 | * @v: pointer of type atomic_t | ||
| 244 | * | ||
| 245 | * The function returns the old value of *v minus 1, even if | ||
| 246 | * the atomic variable, v, was not decremented. | ||
| 247 | */ | ||
| 248 | static inline long atomic64_dec_if_positive(atomic64_t *v) | ||
| 249 | { | ||
| 250 | long old, tmp; | ||
| 251 | smp_mb(); | ||
| 252 | __asm__ __volatile__( | ||
| 253 | "1: ldq_l %[old],%[mem]\n" | ||
| 254 | " subq %[old],1,%[tmp]\n" | ||
| 255 | " ble %[old],2f\n" | ||
| 256 | " stq_c %[tmp],%[mem]\n" | ||
| 257 | " beq %[tmp],3f\n" | ||
| 258 | "2:\n" | ||
| 259 | ".subsection 2\n" | ||
| 260 | "3: br 1b\n" | ||
| 261 | ".previous" | ||
| 262 | : [old] "=&r"(old), [tmp] "=&r"(tmp) | ||
| 263 | : [mem] "m"(*v) | ||
| 264 | : "memory"); | ||
| 265 | smp_mb(); | ||
| 266 | return old - 1; | ||
| 225 | } | 267 | } |
| 226 | 268 | ||
| 227 | #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) | 269 | #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) |
