1/*
2 * Copyright 1995, Russell King.
3 * Various bits and pieces copyrights include:
4 *  Linus Torvalds (test_bit).
5 *
6 * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
7 *
8 * Please note that the code in this file should never be included
9 * from user space.  Many of these are not implemented in assembler
10 * since they would be too costly.  Also, they require priviledged
11 * instructions (which are not available from user mode) to ensure
12 * that they are atomic.
13 */
14
15#ifndef __ASM_ARM_BITOPS_H
16#define __ASM_ARM_BITOPS_H
17
18#if __LINUX_ARM_ARCH__ < 5
19
20#include <asm-generic/bitops/__ffs.h>
21#include <asm-generic/bitops/__fls.h>
22#include <asm-generic/bitops/fls.h>
23
24#else
25
26#define PLATFORM_FFS
27#define PLATFORM_FLS
28
29#if !IS_ENABLED(CONFIG_HAS_THUMB2) && CONFIG_IS_ENABLED(SYS_THUMB_BUILD)
30
31unsigned long __fls(unsigned long word);
32unsigned long __ffs(unsigned long word);
33int fls(unsigned int x);
34int ffs(int x);
35
36#else
37
38#include <asm-generic/bitops/builtin-__fls.h>
39#include <asm-generic/bitops/builtin-__ffs.h>
40#include <asm-generic/bitops/builtin-fls.h>
41#include <asm-generic/bitops/builtin-ffs.h>
42
43#endif
44#endif
45
46#include <asm-generic/bitops/fls64.h>
47
48#ifdef __KERNEL__
49
50#ifndef __ASSEMBLY__
51#include <linux/bitops.h>
52#endif
53#include <asm/proc-armv/system.h>
54
55#define smp_mb__before_clear_bit()	do { } while (0)
56#define smp_mb__after_clear_bit()	do { } while (0)
57
58/*
59 * Function prototypes to keep gcc -Wall happy.
60 */
61extern void set_bit(int nr, volatile void * addr);
62
63extern void clear_bit(int nr, volatile void * addr);
64
65extern void change_bit(int nr, volatile void * addr);
66
67static inline void __change_bit(int nr, volatile void *addr)
68{
69	unsigned long mask = BIT_MASK(nr);
70	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
71
72	*p ^= mask;
73}
74
75static inline int __test_and_set_bit(int nr, volatile void *addr)
76{
77	unsigned long mask = BIT_MASK(nr);
78	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
79	unsigned long old = *p;
80
81	*p = old | mask;
82	return (old & mask) != 0;
83}
84
85static inline int test_and_set_bit(int nr, volatile void * addr)
86{
87	unsigned long flags = 0;
88	int out;
89
90	local_irq_save(flags);
91	out = __test_and_set_bit(nr, addr);
92	local_irq_restore(flags);
93
94	return out;
95}
96
97static inline int __test_and_clear_bit(int nr, volatile void *addr)
98{
99	unsigned long mask = BIT_MASK(nr);
100	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
101	unsigned long old = *p;
102
103	*p = old & ~mask;
104	return (old & mask) != 0;
105}
106
107static inline int test_and_clear_bit(int nr, volatile void * addr)
108{
109	unsigned long flags = 0;
110	int out;
111
112	local_irq_save(flags);
113	out = __test_and_clear_bit(nr, addr);
114	local_irq_restore(flags);
115
116	return out;
117}
118
119extern int test_and_change_bit(int nr, volatile void * addr);
120
121static inline int __test_and_change_bit(int nr, volatile void *addr)
122{
123	unsigned long mask = BIT_MASK(nr);
124	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
125	unsigned long old = *p;
126
127	*p = old ^ mask;
128	return (old & mask) != 0;
129}
130
131/*
132 * This routine doesn't need to be atomic.
133 */
134static inline int test_bit(int nr, const void * addr)
135{
136    return ((unsigned char *) addr)[nr >> 3] & (1U << (nr & 7));
137}
138
139static inline int __ilog2(unsigned int x)
140{
141	return fls(x) - 1;
142}
143
144#define ffz(x)  __ffs(~(x))
145
146static inline int find_next_zero_bit(void *addr, int size, int offset)
147{
148	unsigned long *p = ((unsigned long *)addr) + (offset / BITS_PER_LONG);
149	unsigned long result = offset & ~(BITS_PER_LONG - 1);
150	unsigned long tmp;
151
152	if (offset >= size)
153		return size;
154	size -= result;
155	offset &= (BITS_PER_LONG - 1);
156	if (offset) {
157		tmp = *(p++);
158		tmp |= ~0UL >> (BITS_PER_LONG - offset);
159		if (size < BITS_PER_LONG)
160			goto found_first;
161		if (~tmp)
162			goto found_middle;
163		size -= BITS_PER_LONG;
164		result += BITS_PER_LONG;
165	}
166	while (size & ~(BITS_PER_LONG - 1)) {
167		tmp = *(p++);
168		if (~tmp)
169			goto found_middle;
170		result += BITS_PER_LONG;
171		size -= BITS_PER_LONG;
172	}
173	if (!size)
174		return result;
175	tmp = *p;
176
177found_first:
178	tmp |= ~0UL << size;
179found_middle:
180	return result + ffz(tmp);
181}
182
183/*
184 * hweightN: returns the hamming weight (i.e. the number
185 * of bits set) of a N-bit word
186 */
187
188#define hweight32(x) generic_hweight32(x)
189#define hweight16(x) generic_hweight16(x)
190#define hweight8(x) generic_hweight8(x)
191
192#define find_first_zero_bit(addr, size) \
193	find_next_zero_bit((addr), (size), 0)
194
195#define ext2_set_bit			test_and_set_bit
196#define ext2_clear_bit			test_and_clear_bit
197#define ext2_test_bit			test_bit
198#define ext2_find_first_zero_bit	find_first_zero_bit
199#define ext2_find_next_zero_bit		find_next_zero_bit
200
201/* Bitmap functions for the minix filesystem. */
202#define minix_test_and_set_bit(nr,addr)	test_and_set_bit(nr,addr)
203#define minix_set_bit(nr,addr)		set_bit(nr,addr)
204#define minix_test_and_clear_bit(nr,addr)	test_and_clear_bit(nr,addr)
205#define minix_test_bit(nr,addr)		test_bit(nr,addr)
206#define minix_find_first_zero_bit(addr,size)	find_first_zero_bit(addr,size)
207
208#endif /* __KERNEL__ */
209
210#endif /* _ARM_BITOPS_H */
211