ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / include / asm-arm26 / atomic.h
1 /*
2  *  linux/include/asm-arm26/atomic.h
3  *
4  *  Copyright (c) 1996 Russell King.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  *  Changelog:
11  *   27-06-1996 RMK     Created
12  *   13-04-1997 RMK     Made functions atomic!
13  *   07-12-1997 RMK     Upgraded for v2.1.
14  *   26-08-1998 PJB     Added #ifdef __KERNEL__
15  *
16  *  FIXME - its probably worth seeing what these compile into...
17  */
18 #ifndef __ASM_ARM_ATOMIC_H
19 #define __ASM_ARM_ATOMIC_H
20
21 #include <linux/config.h>
22
23 #ifdef CONFIG_SMP
24 #error SMP is NOT supported
25 #endif
26
27 typedef struct { volatile int counter; } atomic_t;
28
29 #define ATOMIC_INIT(i)  { (i) }
30
31 #ifdef __KERNEL__
32 #include <asm/system.h>
33
34 #define atomic_read(v)  ((v)->counter)
35 #define atomic_set(v,i) (((v)->counter) = (i))
36
37 static inline void atomic_add(int i, volatile atomic_t *v)
38 {
39         unsigned long flags;
40
41         local_irq_save(flags);
42         v->counter += i;
43         local_irq_restore(flags);
44 }
45
46 static inline void atomic_sub(int i, volatile atomic_t *v)
47 {
48         unsigned long flags;
49
50         local_irq_save(flags);
51         v->counter -= i;
52         local_irq_restore(flags);
53 }
54
55 static inline void atomic_inc(volatile atomic_t *v)
56 {
57         unsigned long flags;
58
59         local_irq_save(flags);
60         v->counter += 1;
61         local_irq_restore(flags);
62 }
63
64 static inline void atomic_dec(volatile atomic_t *v)
65 {
66         unsigned long flags;
67
68         local_irq_save(flags);
69         v->counter -= 1;
70         local_irq_restore(flags);
71 }
72
73 static inline int atomic_dec_and_test(volatile atomic_t *v)
74 {
75         unsigned long flags;
76         int val;
77
78         local_irq_save(flags);
79         val = v->counter;
80         v->counter = val -= 1;
81         local_irq_restore(flags);
82
83         return val == 0;
84 }
85
86 static inline int atomic_add_negative(int i, volatile atomic_t *v)
87 {
88         unsigned long flags;
89         int val;
90
91         local_irq_save(flags);
92         val = v->counter;
93         v->counter = val += i;
94         local_irq_restore(flags);
95
96         return val < 0;
97 }
98
99 static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
100 {
101         unsigned long flags;
102
103         local_irq_save(flags);
104         *addr &= ~mask;
105         local_irq_restore(flags);
106 }
107
108 /* Atomic operations are already serializing on ARM */
109 #define smp_mb__before_atomic_dec()     barrier()
110 #define smp_mb__after_atomic_dec()      barrier()
111 #define smp_mb__before_atomic_inc()     barrier()
112 #define smp_mb__after_atomic_inc()      barrier()
113
114 #endif
115 #endif