diff options
Diffstat (limited to 'include/asm-generic/atomic.h')
-rw-r--r-- | include/asm-generic/atomic.h | 192 |
1 files changed, 96 insertions, 96 deletions
diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h index 9c79e7603459..56d4d36e1531 100644 --- a/include/asm-generic/atomic.h +++ b/include/asm-generic/atomic.h | |||
@@ -18,14 +18,100 @@ | |||
18 | #include <asm/cmpxchg.h> | 18 | #include <asm/cmpxchg.h> |
19 | #include <asm/barrier.h> | 19 | #include <asm/barrier.h> |
20 | 20 | ||
21 | /* | ||
22 | * atomic_$op() - $op integer to atomic variable | ||
23 | * @i: integer value to $op | ||
24 | * @v: pointer to the atomic variable | ||
25 | * | ||
26 | * Atomically $ops @i to @v. Does not strictly guarantee a memory-barrier, use | ||
27 | * smp_mb__{before,after}_atomic(). | ||
28 | */ | ||
29 | |||
30 | /* | ||
31 | * atomic_$op_return() - $op interer to atomic variable and returns the result | ||
32 | * @i: integer value to $op | ||
33 | * @v: pointer to the atomic variable | ||
34 | * | ||
35 | * Atomically $ops @i to @v. Does imply a full memory barrier. | ||
36 | */ | ||
37 | |||
21 | #ifdef CONFIG_SMP | 38 | #ifdef CONFIG_SMP |
22 | /* Force people to define core atomics */ | 39 | |
23 | # if !defined(atomic_add_return) || !defined(atomic_sub_return) || \ | 40 | /* we can build all atomic primitives from cmpxchg */ |
24 | !defined(atomic_clear_mask) || !defined(atomic_set_mask) | 41 | |
25 | # error "SMP requires a little arch-specific magic" | 42 | #define ATOMIC_OP(op, c_op) \ |
26 | # endif | 43 | static inline void atomic_##op(int i, atomic_t *v) \ |
44 | { \ | ||
45 | int c, old; \ | ||
46 | \ | ||
47 | c = v->counter; \ | ||
48 | while ((old = cmpxchg(&v->counter, c, c c_op i)) != c) \ | ||
49 | c = old; \ | ||
50 | } | ||
51 | |||
52 | #define ATOMIC_OP_RETURN(op, c_op) \ | ||
53 | static inline int atomic_##op##_return(int i, atomic_t *v) \ | ||
54 | { \ | ||
55 | int c, old; \ | ||
56 | \ | ||
57 | c = v->counter; \ | ||
58 | while ((old = cmpxchg(&v->counter, c, c c_op i)) != c) \ | ||
59 | c = old; \ | ||
60 | \ | ||
61 | return c c_op i; \ | ||
62 | } | ||
63 | |||
64 | #else | ||
65 | |||
66 | #include <linux/irqflags.h> | ||
67 | |||
68 | #define ATOMIC_OP(op, c_op) \ | ||
69 | static inline void atomic_##op(int i, atomic_t *v) \ | ||
70 | { \ | ||
71 | unsigned long flags; \ | ||
72 | \ | ||
73 | raw_local_irq_save(flags); \ | ||
74 | v->counter = v->counter c_op i; \ | ||
75 | raw_local_irq_restore(flags); \ | ||
76 | } | ||
77 | |||
78 | #define ATOMIC_OP_RETURN(op, c_op) \ | ||
79 | static inline int atomic_##op##_return(int i, atomic_t *v) \ | ||
80 | { \ | ||
81 | unsigned long flags; \ | ||
82 | int ret; \ | ||
83 | \ | ||
84 | raw_local_irq_save(flags); \ | ||
85 | ret = (v->counter = v->counter c_op i); \ | ||
86 | raw_local_irq_restore(flags); \ | ||
87 | \ | ||
88 | return ret; \ | ||
89 | } | ||
90 | |||
91 | #endif /* CONFIG_SMP */ | ||
92 | |||
93 | #ifndef atomic_add_return | ||
94 | ATOMIC_OP_RETURN(add, +) | ||
95 | #endif | ||
96 | |||
97 | #ifndef atomic_sub_return | ||
98 | ATOMIC_OP_RETURN(sub, -) | ||
99 | #endif | ||
100 | |||
101 | #ifndef atomic_clear_mask | ||
102 | ATOMIC_OP(and, &) | ||
103 | #define atomic_clear_mask(i, v) atomic_and(~(i), (v)) | ||
27 | #endif | 104 | #endif |
28 | 105 | ||
106 | #ifndef atomic_set_mask | ||
107 | #define CONFIG_ARCH_HAS_ATOMIC_OR | ||
108 | ATOMIC_OP(or, |) | ||
109 | #define atomic_set_mask(i, v) atomic_or((i), (v)) | ||
110 | #endif | ||
111 | |||
112 | #undef ATOMIC_OP_RETURN | ||
113 | #undef ATOMIC_OP | ||
114 | |||
29 | /* | 115 | /* |
30 | * Atomic operations that C can't guarantee us. Useful for | 116 | * Atomic operations that C can't guarantee us. Useful for |
31 | * resource counting etc.. | 117 | * resource counting etc.. |
@@ -33,8 +119,6 @@ | |||
33 | 119 | ||
34 | #define ATOMIC_INIT(i) { (i) } | 120 | #define ATOMIC_INIT(i) { (i) } |
35 | 121 | ||
36 | #ifdef __KERNEL__ | ||
37 | |||
38 | /** | 122 | /** |
39 | * atomic_read - read atomic variable | 123 | * atomic_read - read atomic variable |
40 | * @v: pointer of type atomic_t | 124 | * @v: pointer of type atomic_t |
@@ -56,52 +140,6 @@ | |||
56 | 140 | ||
57 | #include <linux/irqflags.h> | 141 | #include <linux/irqflags.h> |
58 | 142 | ||
59 | /** | ||
60 | * atomic_add_return - add integer to atomic variable | ||
61 | * @i: integer value to add | ||
62 | * @v: pointer of type atomic_t | ||
63 | * | ||
64 | * Atomically adds @i to @v and returns the result | ||
65 | */ | ||
66 | #ifndef atomic_add_return | ||
67 | static inline int atomic_add_return(int i, atomic_t *v) | ||
68 | { | ||
69 | unsigned long flags; | ||
70 | int temp; | ||
71 | |||
72 | raw_local_irq_save(flags); /* Don't trace it in an irqsoff handler */ | ||
73 | temp = v->counter; | ||
74 | temp += i; | ||
75 | v->counter = temp; | ||
76 | raw_local_irq_restore(flags); | ||
77 | |||
78 | return temp; | ||
79 | } | ||
80 | #endif | ||
81 | |||
82 | /** | ||
83 | * atomic_sub_return - subtract integer from atomic variable | ||
84 | * @i: integer value to subtract | ||
85 | * @v: pointer of type atomic_t | ||
86 | * | ||
87 | * Atomically subtracts @i from @v and returns the result | ||
88 | */ | ||
89 | #ifndef atomic_sub_return | ||
90 | static inline int atomic_sub_return(int i, atomic_t *v) | ||
91 | { | ||
92 | unsigned long flags; | ||
93 | int temp; | ||
94 | |||
95 | raw_local_irq_save(flags); /* Don't trace it in an irqsoff handler */ | ||
96 | temp = v->counter; | ||
97 | temp -= i; | ||
98 | v->counter = temp; | ||
99 | raw_local_irq_restore(flags); | ||
100 | |||
101 | return temp; | ||
102 | } | ||
103 | #endif | ||
104 | |||
105 | static inline int atomic_add_negative(int i, atomic_t *v) | 143 | static inline int atomic_add_negative(int i, atomic_t *v) |
106 | { | 144 | { |
107 | return atomic_add_return(i, v) < 0; | 145 | return atomic_add_return(i, v) < 0; |
@@ -139,49 +177,11 @@ static inline void atomic_dec(atomic_t *v) | |||
139 | 177 | ||
140 | static inline int __atomic_add_unless(atomic_t *v, int a, int u) | 178 | static inline int __atomic_add_unless(atomic_t *v, int a, int u) |
141 | { | 179 | { |
142 | int c, old; | 180 | int c, old; |
143 | c = atomic_read(v); | 181 | c = atomic_read(v); |
144 | while (c != u && (old = atomic_cmpxchg(v, c, c + a)) != c) | 182 | while (c != u && (old = atomic_cmpxchg(v, c, c + a)) != c) |
145 | c = old; | 183 | c = old; |
146 | return c; | 184 | return c; |
147 | } | ||
148 | |||
149 | /** | ||
150 | * atomic_clear_mask - Atomically clear bits in atomic variable | ||
151 | * @mask: Mask of the bits to be cleared | ||
152 | * @v: pointer of type atomic_t | ||
153 | * | ||
154 | * Atomically clears the bits set in @mask from @v | ||
155 | */ | ||
156 | #ifndef atomic_clear_mask | ||
157 | static inline void atomic_clear_mask(unsigned long mask, atomic_t *v) | ||
158 | { | ||
159 | unsigned long flags; | ||
160 | |||
161 | mask = ~mask; | ||
162 | raw_local_irq_save(flags); /* Don't trace it in a irqsoff handler */ | ||
163 | v->counter &= mask; | ||
164 | raw_local_irq_restore(flags); | ||
165 | } | 185 | } |
166 | #endif | ||
167 | |||
168 | /** | ||
169 | * atomic_set_mask - Atomically set bits in atomic variable | ||
170 | * @mask: Mask of the bits to be set | ||
171 | * @v: pointer of type atomic_t | ||
172 | * | ||
173 | * Atomically sets the bits set in @mask in @v | ||
174 | */ | ||
175 | #ifndef atomic_set_mask | ||
176 | static inline void atomic_set_mask(unsigned int mask, atomic_t *v) | ||
177 | { | ||
178 | unsigned long flags; | ||
179 | |||
180 | raw_local_irq_save(flags); /* Don't trace it in a irqsoff handler */ | ||
181 | v->counter |= mask; | ||
182 | raw_local_irq_restore(flags); | ||
183 | } | ||
184 | #endif | ||
185 | 186 | ||
186 | #endif /* __KERNEL__ */ | ||
187 | #endif /* __ASM_GENERIC_ATOMIC_H */ | 187 | #endif /* __ASM_GENERIC_ATOMIC_H */ |