Root/target/linux/ubicom32/files/arch/ubicom32/include/asm/atomic.h

1/*
2 * arch/ubicom32/include/asm/atomic.h
3 * Atomic operations definitions for Ubicom32 architecture.
4 *
5 * (C) Copyright 2009, Ubicom, Inc.
6 *
7 * This file is part of the Ubicom32 Linux Kernel Port.
8 *
9 * The Ubicom32 Linux Kernel Port is free software: you can redistribute
10 * it and/or modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation, either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * The Ubicom32 Linux Kernel Port is distributed in the hope that it
15 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
16 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with the Ubicom32 Linux Kernel Port. If not,
21 * see <http://www.gnu.org/licenses/>.
22 *
23 * Ubicom32 implementation derived from (with many thanks):
24 * arch/m68knommu
25 * arch/blackfin
26 * arch/parisc
27 */
28#ifndef _ASM_UBICOM32_ATOMIC_H
29#define _ASM_UBICOM32_ATOMIC_H
30
31#include <asm/system.h>
32#include <asm/ubicom32-common.h>
33#include <asm/types.h>
34
35/*
36 * Most instructions on the Ubicom32 processor are atomic in that they
37 * execute in one clock cycle. However, Linux has several operations
38 * (e.g. compare and swap) which will require more than a single instruction
39 * to perform. To achieve this, the Ubicom32 processor uses a single
40 * global bit in a scratchpad register as a critical section lock. All
41 * atomic operations acquire this lock.
42 *
43 * NOTE: To AVOID DEADLOCK(s), the atomic lock must only be used for atomic
44 * operations or by the ldsr to avoid disabling a thread performing an atomic
45 * operation.
46 *
47 * Do not attempt to disable interrupts while holding the atomic operations
48 * lock or you will DEADLOCK the system.
49 */
50
51#define ATOMIC_INIT(i) { (i) }
52
53/*
54 * __atomic_add()
55 * Add i to v and return the result.
56 */
57static inline void __atomic_add(int i, atomic_t *v)
58{
59    atomic_t *vt = v;
60
61    __atomic_lock_acquire();
62    vt->counter += i;
63    __atomic_lock_release();
64}
65
66/*
67 * __atomic_sub()
68 * Subtract i from v and return the result.
69 */
70static inline void __atomic_sub(int i, atomic_t *v)
71{
72    atomic_t *vt = v;
73
74    __atomic_lock_acquire();
75    vt->counter -= i;
76    __atomic_lock_release();
77}
78
79/*
80 * __atomic_add_return()
81 * Add i to v and return the result.
82 *
83 * The implementation here looks rather odd because we appear to be doing
84 * the addition twice. In fact that's exactly what we're doing but with
85 * the ubicom32 instruction set we can do the inner load and add with two
86 * instructions whereas generating both the atomic result and the "ret"
87 * result requires three instructions. The second add is generally only as
88 * costly as a move instruction and in cases where we compare the result
89 * with a constant the compiler can fold two constant values and do a
90 * single instruction, thus saving an instruction overall!
91 *
92 * At the worst we save one instruction inside the atomic lock.
93 */
94static inline int __atomic_add_return(int i, atomic_t *v)
95{
96    int ret;
97    atomic_t *vt = v;
98
99    __atomic_lock_acquire();
100    ret = vt->counter;
101    vt->counter = ret + i;
102    __atomic_lock_release();
103
104    return ret + i;
105}
106
107/*
108 * __atomic_sub_return()
109 * Subtract i from v and return the result.
110 *
111 * The implementation here looks rather odd because we appear to be doing
112 * the subtraction twice. In fact that's exactly what we're doing but with
113 * the ubicom32 instruction set we can do the inner load and sub with two
114 * instructions whereas generating both the atomic result and the "ret"
115 * result requires three instructions. The second sub is generally only as
116 * costly as a move instruction and in cases where we compare the result
117 * with a constant the compiler can fold two constant values and do a
118 * single instruction, thus saving an instruction overall!
119 *
120 * At the worst we save one instruction inside the atomic lock.
121 */
122static inline int __atomic_sub_return(int i, atomic_t *v)
123{
124    int ret;
125    atomic_t *vt = v;
126
127    __atomic_lock_acquire();
128    ret = vt->counter;
129    vt->counter = ret - i;
130    __atomic_lock_release();
131
132    return ret - i;
133}
134
135/*
136 * PUBLIC API FOR ATOMIC!
137 */
138#define atomic_add(i,v) (__atomic_add( ((int)i),(v)))
139#define atomic_sub(i,v) (__atomic_sub( ((int)i),(v)))
140#define atomic_inc(v) (__atomic_add( 1,(v)))
141#define atomic_dec(v) (__atomic_sub( 1,(v)))
142#define atomic_add_return(i,v) (__atomic_add_return( ((int)i),(v)))
143#define atomic_sub_return(i,v) (__atomic_sub_return( ((int)i),(v)))
144#define atomic_inc_return(v) (__atomic_add_return( 1,(v)))
145#define atomic_dec_return(v) (__atomic_sub_return( 1,(v)))
146#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
147#define atomic_dec_and_test(v) (atomic_dec_return(v) == 0)
148#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0)
149#define atomic_sub_and_test(i,v) (atomic_sub_return((i),(v)) == 0)
150
151/*
152 * atomic_read()
153 * Acquire the atomic lock and read the variable.
154 */
155static inline int atomic_read(const atomic_t *v)
156{
157    int ret;
158    const atomic_t *vt = v;
159
160    __atomic_lock_acquire();
161    ret = vt->counter;
162    __atomic_lock_release();
163
164    return ret;
165}
166
167/*
168 * atomic_set()
169 * Acquire the atomic lock and set the variable.
170 */
171static inline void atomic_set(atomic_t *v, int i)
172{
173    atomic_t *vt = v;
174
175    __atomic_lock_acquire();
176    vt->counter = i;
177    __atomic_lock_release();
178}
179
180/*
181 * atomic_cmpxchg
182 * Acquire the atomic lock and exchange if current == old.
183 */
184static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
185{
186    int prev;
187    atomic_t *vt = v;
188
189    __atomic_lock_acquire();
190    prev = vt->counter;
191    if (prev == old) {
192        vt->counter = new;
193    }
194    __atomic_lock_release();
195
196    return prev;
197}
198
199/*
200 * atomic_xchg()
201 * Acquire the atomic lock and exchange values.
202 */
203static inline int atomic_xchg(atomic_t *v, int new)
204{
205    int prev;
206    atomic_t *vt = v;
207
208    __atomic_lock_acquire();
209    prev = vt->counter;
210    vt->counter = new;
211    __atomic_lock_release();
212
213    return prev;
214}
215
216/*
217 * atomic_add_unless()
218 * Acquire the atomic lock and add a unless the value is u.
219 */
220static inline int atomic_add_unless(atomic_t *v, int a, int u)
221{
222    int prev;
223    atomic_t *vt = v;
224
225    __atomic_lock_acquire();
226    prev = vt->counter;
227    if (prev != u) {
228        vt->counter += a;
229        __atomic_lock_release();
230        return 1;
231    }
232
233    __atomic_lock_release();
234    return 0;
235}
236
237#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
238
239#include <linux/version.h>
240#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
241#include <asm-generic/atomic-long.h>
242#else
243#include <asm-generic/atomic.h>
244#endif
245
246/*
247 * The following is not a real function. The compiler should remove the function
248 * call as long as the user does not pass in a size that __xchg and __cmpxchg
249 * are not prepared for. If the user does pass in an unknown size, the user
250 * will get a link time error.
251 *
252 * The no return is to prevent a compiler error that can occur when dealing with
253 * uninitialized variables. Given that the function doesn't exist there is no
254 * net effect (and if it did it would not return).
255 */
256extern void __xchg_called_with_bad_pointer(void) __attribute__((noreturn));
257
258/*
259 * __xchg()
260 * Xchange *ptr for x atomically.
261 *
262 * Must be both locally atomic and atomic on SMP. Ubicom32 does not have an
263 * atomic exchange instruction so we use the global atomic_lock.
264 */
265static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
266{
267    unsigned long ret;
268
269    __atomic_lock_acquire();
270
271    switch (size) {
272    case 1:
273        ret = *(volatile unsigned char *)ptr;
274        *(volatile unsigned char *)ptr = x;
275        break;
276
277    case 2:
278        ret = *(volatile unsigned short *)ptr;
279        *(volatile unsigned short *)ptr = x;
280        break;
281
282    case 4:
283        ret = *(volatile unsigned int *)ptr;
284        *(volatile unsigned int *)ptr = x;
285        break;
286
287    default:
288        __xchg_called_with_bad_pointer();
289        break;
290    }
291    __atomic_lock_release();
292    return ret;
293}
294
295#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
296
297/*
298 * __cmpxchg()
299 * Compare and Xchange *ptr for x atomically.
300 *
301 * Must be both locally atomic and atomic on SMP. Ubicom32 does not have an
302 * atomic exchange instruction so we use the global atomic_lock.
303 */
304static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, unsigned long next, int size)
305{
306    unsigned long prev;
307
308    __atomic_lock_acquire();
309    switch (size) {
310    case 1:
311        prev = *(u8 *)ptr;
312        if (prev == old) {
313            *(u8 *)ptr = (u8)next;
314        }
315        break;
316
317    case 2:
318        prev = *(u16 *)ptr;
319        if (prev == old) {
320            *(u16 *)ptr = (u16)next;
321        }
322        break;
323
324    case 4:
325        prev = *(u32 *)ptr;
326        if (prev == old) {
327            *(u32 *)ptr = (u32)next;
328        }
329        break;
330
331    default:
332        __xchg_called_with_bad_pointer();
333        break;
334    }
335    __atomic_lock_release();
336    return prev;
337}
338
339/*
340 * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
341 * them available.
342 */
343#define cmpxchg_local(ptr, o, n) \
344    ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), (unsigned long)(n), sizeof(*(ptr))))
345
346#define cmpxchg(ptr, o, n) __cmpxchg((ptr), (o), (n), sizeof(*(ptr)))
347
348#define smp_mb__before_atomic_inc() asm volatile ("" : : : "memory")
349#define smp_mb__after_atomic_inc() asm volatile ("" : : : "memory")
350#define smp_mb__before_atomic_dec() asm volatile ("" : : : "memory")
351#define smp_mb__after_atomic_dec() asm volatile ("" : : : "memory")
352
353#endif /* _ASM_UBICOM32_ATOMIC_H */
354

Archive Download this file



interactive