sh: SH7710VoIPGW board support.
[linux-2.6] / include / asm-generic / bitops / atomic.h
1 #ifndef _ASM_GENERIC_BITOPS_ATOMIC_H_
2 #define _ASM_GENERIC_BITOPS_ATOMIC_H_
3
4 #include <asm/types.h>
5
6 #define BITOP_MASK(nr)          (1UL << ((nr) % BITS_PER_LONG))
7 #define BITOP_WORD(nr)          ((nr) / BITS_PER_LONG)
8
9 #ifdef CONFIG_SMP
10 #include <asm/spinlock.h>
11 #include <asm/cache.h>          /* we use L1_CACHE_BYTES */
12
13 /* Use an array of spinlocks for our atomic_ts.
14  * Hash function to index into a different SPINLOCK.
15  * Since "a" is usually an address, use one spinlock per cacheline.
16  */
17 #  define ATOMIC_HASH_SIZE 4
18 #  define ATOMIC_HASH(a) (&(__atomic_hash[ (((unsigned long) a)/L1_CACHE_BYTES) & (ATOMIC_HASH_SIZE-1) ]))
19
20 extern raw_spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned;
21
22 /* Can't use raw_spin_lock_irq because of #include problems, so
23  * this is the substitute */
24 #define _atomic_spin_lock_irqsave(l,f) do {     \
25         raw_spinlock_t *s = ATOMIC_HASH(l);     \
26         local_irq_save(f);                      \
27         __raw_spin_lock(s);                     \
28 } while(0)
29
30 #define _atomic_spin_unlock_irqrestore(l,f) do {        \
31         raw_spinlock_t *s = ATOMIC_HASH(l);             \
32         __raw_spin_unlock(s);                           \
33         local_irq_restore(f);                           \
34 } while(0)
35
36
37 #else
38 #  define _atomic_spin_lock_irqsave(l,f) do { local_irq_save(f); } while (0)
39 #  define _atomic_spin_unlock_irqrestore(l,f) do { local_irq_restore(f); } while (0)
40 #endif
41
42 /*
43  * NMI events can occur at any time, including when interrupts have been
44  * disabled by *_irqsave().  So you can get NMI events occurring while a
45  * *_bit function is holding a spin lock.  If the NMI handler also wants
46  * to do bit manipulation (and they do) then you can get a deadlock
47  * between the original caller of *_bit() and the NMI handler.
48  *
49  * by Keith Owens
50  */
51
52 /**
53  * set_bit - Atomically set a bit in memory
54  * @nr: the bit to set
55  * @addr: the address to start counting from
56  *
57  * This function is atomic and may not be reordered.  See __set_bit()
58  * if you do not require the atomic guarantees.
59  *
60  * Note: there are no guarantees that this function will not be reordered
61  * on non x86 architectures, so if you are writting portable code,
62  * make sure not to rely on its reordering guarantees.
63  *
64  * Note that @nr may be almost arbitrarily large; this function is not
65  * restricted to acting on a single-word quantity.
66  */
67 static inline void set_bit(int nr, volatile unsigned long *addr)
68 {
69         unsigned long mask = BITOP_MASK(nr);
70         unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
71         unsigned long flags;
72
73         _atomic_spin_lock_irqsave(p, flags);
74         *p  |= mask;
75         _atomic_spin_unlock_irqrestore(p, flags);
76 }
77
78 /**
79  * clear_bit - Clears a bit in memory
80  * @nr: Bit to clear
81  * @addr: Address to start counting from
82  *
83  * clear_bit() is atomic and may not be reordered.  However, it does
84  * not contain a memory barrier, so if it is used for locking purposes,
85  * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
86  * in order to ensure changes are visible on other processors.
87  */
88 static inline void clear_bit(int nr, volatile unsigned long *addr)
89 {
90         unsigned long mask = BITOP_MASK(nr);
91         unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
92         unsigned long flags;
93
94         _atomic_spin_lock_irqsave(p, flags);
95         *p &= ~mask;
96         _atomic_spin_unlock_irqrestore(p, flags);
97 }
98
99 /**
100  * change_bit - Toggle a bit in memory
101  * @nr: Bit to change
102  * @addr: Address to start counting from
103  *
104  * change_bit() is atomic and may not be reordered. It may be
105  * reordered on other architectures than x86.
106  * Note that @nr may be almost arbitrarily large; this function is not
107  * restricted to acting on a single-word quantity.
108  */
109 static inline void change_bit(int nr, volatile unsigned long *addr)
110 {
111         unsigned long mask = BITOP_MASK(nr);
112         unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
113         unsigned long flags;
114
115         _atomic_spin_lock_irqsave(p, flags);
116         *p ^= mask;
117         _atomic_spin_unlock_irqrestore(p, flags);
118 }
119
120 /**
121  * test_and_set_bit - Set a bit and return its old value
122  * @nr: Bit to set
123  * @addr: Address to count from
124  *
125  * This operation is atomic and cannot be reordered.
126  * It may be reordered on other architectures than x86.
127  * It also implies a memory barrier.
128  */
129 static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
130 {
131         unsigned long mask = BITOP_MASK(nr);
132         unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
133         unsigned long old;
134         unsigned long flags;
135
136         _atomic_spin_lock_irqsave(p, flags);
137         old = *p;
138         *p = old | mask;
139         _atomic_spin_unlock_irqrestore(p, flags);
140
141         return (old & mask) != 0;
142 }
143
144 /**
145  * test_and_clear_bit - Clear a bit and return its old value
146  * @nr: Bit to clear
147  * @addr: Address to count from
148  *
149  * This operation is atomic and cannot be reordered.
150  * It can be reorderdered on other architectures other than x86.
151  * It also implies a memory barrier.
152  */
153 static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
154 {
155         unsigned long mask = BITOP_MASK(nr);
156         unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
157         unsigned long old;
158         unsigned long flags;
159
160         _atomic_spin_lock_irqsave(p, flags);
161         old = *p;
162         *p = old & ~mask;
163         _atomic_spin_unlock_irqrestore(p, flags);
164
165         return (old & mask) != 0;
166 }
167
168 /**
169  * test_and_change_bit - Change a bit and return its old value
170  * @nr: Bit to change
171  * @addr: Address to count from
172  *
173  * This operation is atomic and cannot be reordered.
174  * It also implies a memory barrier.
175  */
176 static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
177 {
178         unsigned long mask = BITOP_MASK(nr);
179         unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
180         unsigned long old;
181         unsigned long flags;
182
183         _atomic_spin_lock_irqsave(p, flags);
184         old = *p;
185         *p = old ^ mask;
186         _atomic_spin_unlock_irqrestore(p, flags);
187
188         return (old & mask) != 0;
189 }
190
191 #endif /* _ASM_GENERIC_BITOPS_ATOMIC_H */