Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
1da177e4 LT |
2 | #ifndef _PARISC_BITOPS_H |
3 | #define _PARISC_BITOPS_H | |
0624517d JS |
4 | |
5 | #ifndef _LINUX_BITOPS_H | |
6 | #error only <linux/bitops.h> can be included directly | |
7 | #endif | |
1da177e4 LT |
8 | |
9 | #include <linux/compiler.h> | |
2ad5d52d | 10 | #include <asm/types.h> |
1da177e4 | 11 | #include <asm/byteorder.h> |
e4a65e9d | 12 | #include <asm/barrier.h> |
60063497 | 13 | #include <linux/atomic.h> |
1da177e4 LT |
14 | |
15 | /* | |
16 | * HP-PARISC specific bit operations | |
17 | * for a detailed description of the functions please refer | |
18 | * to include/asm-i386/bitops.h or kerneldoc | |
19 | */ | |
20 | ||
2ad5d52d HD |
21 | #if __BITS_PER_LONG == 64 |
22 | #define SHIFT_PER_LONG 6 | |
23 | #else | |
24 | #define SHIFT_PER_LONG 5 | |
25 | #endif | |
26 | ||
a366064c | 27 | #define CHOP_SHIFTCOUNT(x) (((unsigned long) (x)) & (BITS_PER_LONG - 1)) |
1da177e4 LT |
28 | |
29 | ||
a366064c GG |
30 | /* See http://marc.theaimsgroup.com/?t=108826637900003 for discussion |
31 | * on use of volatile and __*_bit() (set/clear/change): | |
32 | * *_bit() want use of volatile. | |
33 | * __*_bit() are "relaxed" and don't use spinlock or volatile. | |
34 | */ | |
35 | ||
36 | static __inline__ void set_bit(int nr, volatile unsigned long * addr) | |
1da177e4 | 37 | { |
a366064c | 38 | unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr); |
1da177e4 LT |
39 | unsigned long flags; |
40 | ||
41 | addr += (nr >> SHIFT_PER_LONG); | |
1da177e4 LT |
42 | _atomic_spin_lock_irqsave(addr, flags); |
43 | *addr |= mask; | |
44 | _atomic_spin_unlock_irqrestore(addr, flags); | |
45 | } | |
46 | ||
a366064c | 47 | static __inline__ void clear_bit(int nr, volatile unsigned long * addr) |
1da177e4 | 48 | { |
a366064c | 49 | unsigned long mask = ~(1UL << CHOP_SHIFTCOUNT(nr)); |
1da177e4 LT |
50 | unsigned long flags; |
51 | ||
52 | addr += (nr >> SHIFT_PER_LONG); | |
1da177e4 | 53 | _atomic_spin_lock_irqsave(addr, flags); |
a366064c | 54 | *addr &= mask; |
1da177e4 LT |
55 | _atomic_spin_unlock_irqrestore(addr, flags); |
56 | } | |
57 | ||
a366064c | 58 | static __inline__ void change_bit(int nr, volatile unsigned long * addr) |
1da177e4 | 59 | { |
a366064c | 60 | unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr); |
1da177e4 LT |
61 | unsigned long flags; |
62 | ||
63 | addr += (nr >> SHIFT_PER_LONG); | |
1da177e4 LT |
64 | _atomic_spin_lock_irqsave(addr, flags); |
65 | *addr ^= mask; | |
66 | _atomic_spin_unlock_irqrestore(addr, flags); | |
67 | } | |
68 | ||
a366064c | 69 | static __inline__ int test_and_set_bit(int nr, volatile unsigned long * addr) |
1da177e4 | 70 | { |
a366064c | 71 | unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr); |
af5917f0 | 72 | unsigned long old; |
1da177e4 | 73 | unsigned long flags; |
af5917f0 | 74 | int set; |
1da177e4 LT |
75 | |
76 | addr += (nr >> SHIFT_PER_LONG); | |
1da177e4 | 77 | _atomic_spin_lock_irqsave(addr, flags); |
af5917f0 MW |
78 | old = *addr; |
79 | set = (old & mask) ? 1 : 0; | |
80 | if (!set) | |
81 | *addr = old | mask; | |
1da177e4 LT |
82 | _atomic_spin_unlock_irqrestore(addr, flags); |
83 | ||
af5917f0 | 84 | return set; |
1da177e4 LT |
85 | } |
86 | ||
a366064c | 87 | static __inline__ int test_and_clear_bit(int nr, volatile unsigned long * addr) |
1da177e4 | 88 | { |
a366064c | 89 | unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr); |
af5917f0 | 90 | unsigned long old; |
1da177e4 | 91 | unsigned long flags; |
af5917f0 | 92 | int set; |
1da177e4 LT |
93 | |
94 | addr += (nr >> SHIFT_PER_LONG); | |
1da177e4 | 95 | _atomic_spin_lock_irqsave(addr, flags); |
af5917f0 MW |
96 | old = *addr; |
97 | set = (old & mask) ? 1 : 0; | |
98 | if (set) | |
99 | *addr = old & ~mask; | |
1da177e4 LT |
100 | _atomic_spin_unlock_irqrestore(addr, flags); |
101 | ||
af5917f0 | 102 | return set; |
1da177e4 LT |
103 | } |
104 | ||
a366064c | 105 | static __inline__ int test_and_change_bit(int nr, volatile unsigned long * addr) |
1da177e4 | 106 | { |
a366064c GG |
107 | unsigned long mask = 1UL << CHOP_SHIFTCOUNT(nr); |
108 | unsigned long oldbit; | |
1da177e4 LT |
109 | unsigned long flags; |
110 | ||
111 | addr += (nr >> SHIFT_PER_LONG); | |
1da177e4 | 112 | _atomic_spin_lock_irqsave(addr, flags); |
a366064c GG |
113 | oldbit = *addr; |
114 | *addr = oldbit ^ mask; | |
1da177e4 LT |
115 | _atomic_spin_unlock_irqrestore(addr, flags); |
116 | ||
a366064c | 117 | return (oldbit & mask) ? 1 : 0; |
1da177e4 LT |
118 | } |
119 | ||
59e18a2e | 120 | #include <asm-generic/bitops/non-atomic.h> |
1da177e4 LT |
121 | |
122 | #ifdef __KERNEL__ | |
123 | ||
124 | /** | |
125 | * __ffs - find first bit in word. returns 0 to "BITS_PER_LONG-1". | |
126 | * @word: The word to search | |
127 | * | |
128 | * __ffs() return is undefined if no bit is set. | |
129 | * | |
130 | * 32-bit fast __ffs by LaMont Jones "lamont At hp com". | |
131 | * 64-bit enhancement by Grant Grundler "grundler At parisc-linux org". | |
132 | * (with help from willy/jejb to get the semantics right) | |
133 | * | |
134 | * This algorithm avoids branches by making use of nullification. | |
135 | * One side effect of "extr" instructions is it sets PSW[N] bit. | |
136 | * How PSW[N] (nullify next insn) gets set is determined by the | |
137 | * "condition" field (eg "<>" or "TR" below) in the extr* insn. | |
138 | * Only the 1st and one of either the 2cd or 3rd insn will get executed. | |
139 | * Each set of 3 insn will get executed in 2 cycles on PA8x00 vs 16 or so | |
140 | * cycles for each mispredicted branch. | |
141 | */ | |
142 | ||
143 | static __inline__ unsigned long __ffs(unsigned long x) | |
144 | { | |
145 | unsigned long ret; | |
146 | ||
147 | __asm__( | |
513e7ecd | 148 | #ifdef CONFIG_64BIT |
1da177e4 LT |
149 | " ldi 63,%1\n" |
150 | " extrd,u,*<> %0,63,32,%%r0\n" | |
151 | " extrd,u,*TR %0,31,32,%0\n" /* move top 32-bits down */ | |
152 | " addi -32,%1,%1\n" | |
153 | #else | |
154 | " ldi 31,%1\n" | |
155 | #endif | |
156 | " extru,<> %0,31,16,%%r0\n" | |
157 | " extru,TR %0,15,16,%0\n" /* xxxx0000 -> 0000xxxx */ | |
158 | " addi -16,%1,%1\n" | |
159 | " extru,<> %0,31,8,%%r0\n" | |
160 | " extru,TR %0,23,8,%0\n" /* 0000xx00 -> 000000xx */ | |
161 | " addi -8,%1,%1\n" | |
162 | " extru,<> %0,31,4,%%r0\n" | |
163 | " extru,TR %0,27,4,%0\n" /* 000000x0 -> 0000000x */ | |
164 | " addi -4,%1,%1\n" | |
165 | " extru,<> %0,31,2,%%r0\n" | |
166 | " extru,TR %0,29,2,%0\n" /* 0000000y, 1100b -> 0011b */ | |
167 | " addi -2,%1,%1\n" | |
168 | " extru,= %0,31,1,%%r0\n" /* check last bit */ | |
169 | " addi -1,%1,%1\n" | |
170 | : "+r" (x), "=r" (ret) ); | |
171 | return ret; | |
172 | } | |
173 | ||
59e18a2e | 174 | #include <asm-generic/bitops/ffz.h> |
1da177e4 LT |
175 | |
176 | /* | |
177 | * ffs: find first bit set. returns 1 to BITS_PER_LONG or 0 (if none set) | |
178 | * This is defined the same way as the libc and compiler builtin | |
179 | * ffs routines, therefore differs in spirit from the above ffz (man ffs). | |
180 | */ | |
181 | static __inline__ int ffs(int x) | |
182 | { | |
183 | return x ? (__ffs((unsigned long)x) + 1) : 0; | |
184 | } | |
185 | ||
186 | /* | |
187 | * fls: find last (most significant) bit set. | |
188 | * fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. | |
189 | */ | |
190 | ||
191 | static __inline__ int fls(int x) | |
192 | { | |
193 | int ret; | |
194 | if (!x) | |
195 | return 0; | |
196 | ||
197 | __asm__( | |
198 | " ldi 1,%1\n" | |
199 | " extru,<> %0,15,16,%%r0\n" | |
200 | " zdep,TR %0,15,16,%0\n" /* xxxx0000 */ | |
201 | " addi 16,%1,%1\n" | |
202 | " extru,<> %0,7,8,%%r0\n" | |
203 | " zdep,TR %0,23,24,%0\n" /* xx000000 */ | |
204 | " addi 8,%1,%1\n" | |
205 | " extru,<> %0,3,4,%%r0\n" | |
206 | " zdep,TR %0,27,28,%0\n" /* x0000000 */ | |
207 | " addi 4,%1,%1\n" | |
208 | " extru,<> %0,1,2,%%r0\n" | |
209 | " zdep,TR %0,29,30,%0\n" /* y0000000 (y&3 = 0) */ | |
210 | " addi 2,%1,%1\n" | |
211 | " extru,= %0,0,1,%%r0\n" | |
212 | " addi 1,%1,%1\n" /* if y & 8, add 1 */ | |
213 | : "+r" (x), "=r" (ret) ); | |
214 | ||
215 | return ret; | |
216 | } | |
217 | ||
56a6b1eb | 218 | #include <asm-generic/bitops/__fls.h> |
59e18a2e AM |
219 | #include <asm-generic/bitops/fls64.h> |
220 | #include <asm-generic/bitops/hweight.h> | |
26333576 | 221 | #include <asm-generic/bitops/lock.h> |
59e18a2e | 222 | #include <asm-generic/bitops/sched.h> |
1da177e4 LT |
223 | |
224 | #endif /* __KERNEL__ */ | |
225 | ||
59e18a2e | 226 | #include <asm-generic/bitops/find.h> |
1da177e4 LT |
227 | |
228 | #ifdef __KERNEL__ | |
59e18a2e | 229 | |
861b5ae7 | 230 | #include <asm-generic/bitops/le.h> |
148817ba | 231 | #include <asm-generic/bitops/ext2-atomic-setbit.h> |
a366064c GG |
232 | |
233 | #endif /* __KERNEL__ */ | |
1da177e4 | 234 | |
1da177e4 | 235 | #endif /* _PARISC_BITOPS_H */ |