blob: 8e897833bb144b6c4ac12d26c2ecc5852dc6b08b [file] [log] [blame]
wdenkc6097192002-11-03 00:24:07 +00001/*
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
Sean Anderson6babd842023-07-31 17:27:33 -040018#if __LINUX_ARM_ARCH__ < 5
19
Grygorii Strashkoced66ce2018-06-28 14:25:52 -050020#include <asm-generic/bitops/__ffs.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060021#include <asm-generic/bitops/__fls.h>
22#include <asm-generic/bitops/fls.h>
Sean Anderson6babd842023-07-31 17:27:33 -040023
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
Simon Glass4dcacfc2020-05-10 11:40:13 -060046#include <asm-generic/bitops/fls64.h>
Grygorii Strashkoced66ce2018-06-28 14:25:52 -050047
wdenkc6097192002-11-03 00:24:07 +000048#ifdef __KERNEL__
49
Simon Glass4dcacfc2020-05-10 11:40:13 -060050#ifndef __ASSEMBLY__
51#include <linux/bitops.h>
52#endif
Vasili Galka8e53b1e2014-06-10 16:16:14 +030053#include <asm/proc-armv/system.h>
Simon Kagstrom209a72e2009-08-24 09:10:16 +020054
wdenkc6097192002-11-03 00:24:07 +000055#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
wdenkc6097192002-11-03 00:24:07 +000063extern void clear_bit(int nr, volatile void * addr);
64
wdenkc6097192002-11-03 00:24:07 +000065extern void change_bit(int nr, volatile void * addr);
66
67static inline void __change_bit(int nr, volatile void *addr)
68{
Simon Kagstrom6fc58222009-08-24 09:10:03 +020069 unsigned long mask = BIT_MASK(nr);
70 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
71
72 *p ^= mask;
wdenkc6097192002-11-03 00:24:07 +000073}
74
wdenkc6097192002-11-03 00:24:07 +000075static inline int __test_and_set_bit(int nr, volatile void *addr)
76{
Simon Kagstrom6fc58222009-08-24 09:10:03 +020077 unsigned long mask = BIT_MASK(nr);
78 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
79 unsigned long old = *p;
wdenkc6097192002-11-03 00:24:07 +000080
Simon Kagstrom6fc58222009-08-24 09:10:03 +020081 *p = old | mask;
82 return (old & mask) != 0;
wdenkc6097192002-11-03 00:24:07 +000083}
84
Simon Kagstrom209a72e2009-08-24 09:10:16 +020085static inline int test_and_set_bit(int nr, volatile void * addr)
86{
Heiko Schocher3c6392f2015-11-30 08:47:42 +010087 unsigned long flags = 0;
Simon Kagstrom209a72e2009-08-24 09:10:16 +020088 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}
wdenkc6097192002-11-03 00:24:07 +000096
97static inline int __test_and_clear_bit(int nr, volatile void *addr)
98{
Simon Kagstrom6fc58222009-08-24 09:10:03 +020099 unsigned long mask = BIT_MASK(nr);
100 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
101 unsigned long old = *p;
wdenkc6097192002-11-03 00:24:07 +0000102
Simon Kagstrom6fc58222009-08-24 09:10:03 +0200103 *p = old & ~mask;
104 return (old & mask) != 0;
wdenkc6097192002-11-03 00:24:07 +0000105}
106
Simon Kagstrom209a72e2009-08-24 09:10:16 +0200107static inline int test_and_clear_bit(int nr, volatile void * addr)
108{
Heiko Schocher3c6392f2015-11-30 08:47:42 +0100109 unsigned long flags = 0;
Simon Kagstrom209a72e2009-08-24 09:10:16 +0200110 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
wdenkc6097192002-11-03 00:24:07 +0000119extern int test_and_change_bit(int nr, volatile void * addr);
120
121static inline int __test_and_change_bit(int nr, volatile void *addr)
122{
Simon Kagstrom6fc58222009-08-24 09:10:03 +0200123 unsigned long mask = BIT_MASK(nr);
124 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
125 unsigned long old = *p;
wdenkc6097192002-11-03 00:24:07 +0000126
Simon Kagstrom6fc58222009-08-24 09:10:03 +0200127 *p = old ^ mask;
128 return (old & mask) != 0;
wdenkc6097192002-11-03 00:24:07 +0000129}
130
wdenkc6097192002-11-03 00:24:07 +0000131/*
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
Rob Herringa6357cb2011-07-05 04:38:51 +0000139static inline int __ilog2(unsigned int x)
140{
Sean Anderson6babd842023-07-31 17:27:33 -0400141 return fls(x) - 1;
Rob Herringa6357cb2011-07-05 04:38:51 +0000142}
143
Grygorii Strashkoced66ce2018-06-28 14:25:52 -0500144#define ffz(x) __ffs(~(x))
wdenkc6097192002-11-03 00:24:07 +0000145
Vitaly Andrianov3bd82c52015-02-05 11:24:46 -0500146static inline int find_next_zero_bit(void *addr, int size, int offset)
147{
Grygorii Strashkoced66ce2018-06-28 14:25:52 -0500148 unsigned long *p = ((unsigned long *)addr) + (offset / BITS_PER_LONG);
149 unsigned long result = offset & ~(BITS_PER_LONG - 1);
Vitaly Andrianov3bd82c52015-02-05 11:24:46 -0500150 unsigned long tmp;
151
152 if (offset >= size)
153 return size;
154 size -= result;
Grygorii Strashkoced66ce2018-06-28 14:25:52 -0500155 offset &= (BITS_PER_LONG - 1);
Vitaly Andrianov3bd82c52015-02-05 11:24:46 -0500156 if (offset) {
157 tmp = *(p++);
Grygorii Strashkoced66ce2018-06-28 14:25:52 -0500158 tmp |= ~0UL >> (BITS_PER_LONG - offset);
159 if (size < BITS_PER_LONG)
Vitaly Andrianov3bd82c52015-02-05 11:24:46 -0500160 goto found_first;
161 if (~tmp)
162 goto found_middle;
Grygorii Strashkoced66ce2018-06-28 14:25:52 -0500163 size -= BITS_PER_LONG;
164 result += BITS_PER_LONG;
Vitaly Andrianov3bd82c52015-02-05 11:24:46 -0500165 }
Grygorii Strashkoced66ce2018-06-28 14:25:52 -0500166 while (size & ~(BITS_PER_LONG - 1)) {
Vitaly Andrianov3bd82c52015-02-05 11:24:46 -0500167 tmp = *(p++);
168 if (~tmp)
169 goto found_middle;
Grygorii Strashkoced66ce2018-06-28 14:25:52 -0500170 result += BITS_PER_LONG;
171 size -= BITS_PER_LONG;
Vitaly Andrianov3bd82c52015-02-05 11:24:46 -0500172 }
173 if (!size)
174 return result;
175 tmp = *p;
176
177found_first:
Grygorii Strashkocdcda672018-04-27 19:58:49 -0500178 tmp |= ~0UL << size;
Vitaly Andrianov3bd82c52015-02-05 11:24:46 -0500179found_middle:
180 return result + ffz(tmp);
181}
182
wdenkc6097192002-11-03 00:24:07 +0000183/*
wdenkc6097192002-11-03 00:24:07 +0000184 * 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
Vitaly Andrianov3bd82c52015-02-05 11:24:46 -0500192#define find_first_zero_bit(addr, size) \
193 find_next_zero_bit((addr), (size), 0)
194
wdenkc6097192002-11-03 00:24:07 +0000195#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
wdenkc6097192002-11-03 00:24:07 +0000210#endif /* _ARM_BITOPS_H */