1#ifndef _ASM_GENERIC_BITOPS_ATOMIC_H_
2#define _ASM_GENERIC_BITOPS_ATOMIC_H_
3
4#include <asm/types.h>
5
6#ifdef CONFIG_SMP
7#include <asm/spinlock.h>
8#include <asm/cache.h>
9
10
11
12
13
14# define ATOMIC_HASH_SIZE 4
15# define ATOMIC_HASH(a) (&(__atomic_hash[ (((unsigned long) a)/L1_CACHE_BYTES) & (ATOMIC_HASH_SIZE-1) ]))
16
17extern raw_spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned;
18
19
20
21#define _atomic_spin_lock_irqsave(l,f) do { \
22 raw_spinlock_t *s = ATOMIC_HASH(l); \
23 local_irq_save(f); \
24 __raw_spin_lock(s); \
25} while(0)
26
27#define _atomic_spin_unlock_irqrestore(l,f) do { \
28 raw_spinlock_t *s = ATOMIC_HASH(l); \
29 __raw_spin_unlock(s); \
30 local_irq_restore(f); \
31} while(0)
32
33
34#else
35# define _atomic_spin_lock_irqsave(l,f) do { local_irq_save(f); } while (0)
36# define _atomic_spin_unlock_irqrestore(l,f) do { local_irq_restore(f); } while (0)
37#endif
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64static inline void set_bit(int nr, volatile unsigned long *addr)
65{
66 unsigned long mask = BIT_MASK(nr);
67 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
68 unsigned long flags;
69
70 _atomic_spin_lock_irqsave(p, flags);
71 *p |= mask;
72 _atomic_spin_unlock_irqrestore(p, flags);
73}
74
75
76
77
78
79
80
81
82
83
84
85static inline void clear_bit(int nr, volatile unsigned long *addr)
86{
87 unsigned long mask = BIT_MASK(nr);
88 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
89 unsigned long flags;
90
91 _atomic_spin_lock_irqsave(p, flags);
92 *p &= ~mask;
93 _atomic_spin_unlock_irqrestore(p, flags);
94}
95
96
97
98
99
100
101
102
103
104
105
106static inline void change_bit(int nr, volatile unsigned long *addr)
107{
108 unsigned long mask = BIT_MASK(nr);
109 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
110 unsigned long flags;
111
112 _atomic_spin_lock_irqsave(p, flags);
113 *p ^= mask;
114 _atomic_spin_unlock_irqrestore(p, flags);
115}
116
117
118
119
120
121
122
123
124
125
126static inline int test_and_set_bit(int nr, volatile unsigned long *addr)
127{
128 unsigned long mask = BIT_MASK(nr);
129 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
130 unsigned long old;
131 unsigned long flags;
132
133 _atomic_spin_lock_irqsave(p, flags);
134 old = *p;
135 *p = old | mask;
136 _atomic_spin_unlock_irqrestore(p, flags);
137
138 return (old & mask) != 0;
139}
140
141
142
143
144
145
146
147
148
149
150static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
151{
152 unsigned long mask = BIT_MASK(nr);
153 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
154 unsigned long old;
155 unsigned long flags;
156
157 _atomic_spin_lock_irqsave(p, flags);
158 old = *p;
159 *p = old & ~mask;
160 _atomic_spin_unlock_irqrestore(p, flags);
161
162 return (old & mask) != 0;
163}
164
165
166
167
168
169
170
171
172
173static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
174{
175 unsigned long mask = BIT_MASK(nr);
176 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
177 unsigned long old;
178 unsigned long flags;
179
180 _atomic_spin_lock_irqsave(p, flags);
181 old = *p;
182 *p = old ^ mask;
183 _atomic_spin_unlock_irqrestore(p, flags);
184
185 return (old & mask) != 0;
186}
187
188#endif
189