1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
24ade0818SYury Norov #ifndef _TOOLS_LINUX_BITMAP_H
34ade0818SYury Norov #define _TOOLS_LINUX_BITMAP_H
4915b0882SArnaldo Carvalho de Melo
5915b0882SArnaldo Carvalho de Melo #include <string.h>
610a04ff0SAlexander Lobakin #include <linux/align.h>
7915b0882SArnaldo Carvalho de Melo #include <linux/bitops.h>
84ade0818SYury Norov #include <linux/find.h>
998c03296SJiri Olsa #include <stdlib.h>
10c68a2aabSMatthew Wilcox #include <linux/kernel.h>
11915b0882SArnaldo Carvalho de Melo
12915b0882SArnaldo Carvalho de Melo #define DECLARE_BITMAP(name,bits) \
13915b0882SArnaldo Carvalho de Melo unsigned long name[BITS_TO_LONGS(bits)]
14915b0882SArnaldo Carvalho de Melo
154e23eeebSLinus Torvalds unsigned int __bitmap_weight(const unsigned long *bitmap, int bits);
16915b0882SArnaldo Carvalho de Melo void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
17915b0882SArnaldo Carvalho de Melo const unsigned long *bitmap2, int bits);
18e2863a78SYury Norov bool __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
19741c74f5SJiri Olsa const unsigned long *bitmap2, unsigned int bits);
20005f1700SKees Cook bool __bitmap_equal(const unsigned long *bitmap1,
218812ad41SAlexey Budankov const unsigned long *bitmap2, unsigned int bits);
22*82114e45SWei Yang void __bitmap_set(unsigned long *map, unsigned int start, int len);
23692a68eeSWei Yang void __bitmap_clear(unsigned long *map, unsigned int start, int len);
24005f1700SKees Cook bool __bitmap_intersects(const unsigned long *bitmap1,
25f20510d5SAlexey Bayduraev const unsigned long *bitmap2, unsigned int bits);
26915b0882SArnaldo Carvalho de Melo
27915b0882SArnaldo Carvalho de Melo #define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1)))
28a719101fSYury Norov #define BITMAP_LAST_WORD_MASK(nbits) (~0UL >> (-(nbits) & (BITS_PER_LONG - 1)))
29915b0882SArnaldo Carvalho de Melo
30a37fbe66SAlexander Lobakin #define bitmap_size(nbits) (ALIGN(nbits, BITS_PER_LONG) / BITS_PER_BYTE)
31a37fbe66SAlexander Lobakin
bitmap_zero(unsigned long * dst,unsigned int nbits)32e5b9252dSYury Norov static inline void bitmap_zero(unsigned long *dst, unsigned int nbits)
33915b0882SArnaldo Carvalho de Melo {
34915b0882SArnaldo Carvalho de Melo if (small_const_nbits(nbits))
35915b0882SArnaldo Carvalho de Melo *dst = 0UL;
36915b0882SArnaldo Carvalho de Melo else {
37a37fbe66SAlexander Lobakin memset(dst, 0, bitmap_size(nbits));
38915b0882SArnaldo Carvalho de Melo }
39915b0882SArnaldo Carvalho de Melo }
40915b0882SArnaldo Carvalho de Melo
bitmap_fill(unsigned long * dst,unsigned int nbits)41b328daf3SMatthew Wilcox static inline void bitmap_fill(unsigned long *dst, unsigned int nbits)
42b328daf3SMatthew Wilcox {
43b328daf3SMatthew Wilcox unsigned int nlongs = BITS_TO_LONGS(nbits);
44b328daf3SMatthew Wilcox if (!small_const_nbits(nbits)) {
45b328daf3SMatthew Wilcox unsigned int len = (nlongs - 1) * sizeof(unsigned long);
46b328daf3SMatthew Wilcox memset(dst, 0xff, len);
47b328daf3SMatthew Wilcox }
48b328daf3SMatthew Wilcox dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits);
49b328daf3SMatthew Wilcox }
50b328daf3SMatthew Wilcox
bitmap_empty(const unsigned long * src,unsigned int nbits)51e2863a78SYury Norov static inline bool bitmap_empty(const unsigned long *src, unsigned int nbits)
52b328daf3SMatthew Wilcox {
53b328daf3SMatthew Wilcox if (small_const_nbits(nbits))
54b328daf3SMatthew Wilcox return ! (*src & BITMAP_LAST_WORD_MASK(nbits));
55b328daf3SMatthew Wilcox
56b328daf3SMatthew Wilcox return find_first_bit(src, nbits) == nbits;
57b328daf3SMatthew Wilcox }
58b328daf3SMatthew Wilcox
bitmap_full(const unsigned long * src,unsigned int nbits)59e2863a78SYury Norov static inline bool bitmap_full(const unsigned long *src, unsigned int nbits)
60b328daf3SMatthew Wilcox {
61b328daf3SMatthew Wilcox if (small_const_nbits(nbits))
62b328daf3SMatthew Wilcox return ! (~(*src) & BITMAP_LAST_WORD_MASK(nbits));
63b328daf3SMatthew Wilcox
64b328daf3SMatthew Wilcox return find_first_zero_bit(src, nbits) == nbits;
65b328daf3SMatthew Wilcox }
66b328daf3SMatthew Wilcox
bitmap_weight(const unsigned long * src,unsigned int nbits)674e23eeebSLinus Torvalds static inline unsigned int bitmap_weight(const unsigned long *src, unsigned int nbits)
68915b0882SArnaldo Carvalho de Melo {
69915b0882SArnaldo Carvalho de Melo if (small_const_nbits(nbits))
70915b0882SArnaldo Carvalho de Melo return hweight_long(*src & BITMAP_LAST_WORD_MASK(nbits));
71915b0882SArnaldo Carvalho de Melo return __bitmap_weight(src, nbits);
72915b0882SArnaldo Carvalho de Melo }
73915b0882SArnaldo Carvalho de Melo
bitmap_or(unsigned long * dst,const unsigned long * src1,const unsigned long * src2,unsigned int nbits)74915b0882SArnaldo Carvalho de Melo static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
75e5b9252dSYury Norov const unsigned long *src2, unsigned int nbits)
76915b0882SArnaldo Carvalho de Melo {
77915b0882SArnaldo Carvalho de Melo if (small_const_nbits(nbits))
78915b0882SArnaldo Carvalho de Melo *dst = *src1 | *src2;
79915b0882SArnaldo Carvalho de Melo else
80915b0882SArnaldo Carvalho de Melo __bitmap_or(dst, src1, src2, nbits);
81915b0882SArnaldo Carvalho de Melo }
82915b0882SArnaldo Carvalho de Melo
bitmap_alloc(unsigned int nbits,gfp_t flags __maybe_unused)83*82114e45SWei Yang static inline unsigned long *bitmap_alloc(unsigned int nbits, gfp_t flags __maybe_unused)
84*82114e45SWei Yang {
85*82114e45SWei Yang return malloc(bitmap_size(nbits));
86*82114e45SWei Yang }
87*82114e45SWei Yang
88915b0882SArnaldo Carvalho de Melo /**
897fc5b571SAndy Shevchenko * bitmap_zalloc - Allocate bitmap
90e2091cedSJiri Olsa * @nbits: Number of bits
9198c03296SJiri Olsa */
bitmap_zalloc(int nbits)927fc5b571SAndy Shevchenko static inline unsigned long *bitmap_zalloc(int nbits)
9398c03296SJiri Olsa {
94a37fbe66SAlexander Lobakin return calloc(1, bitmap_size(nbits));
9598c03296SJiri Olsa }
9698c03296SJiri Olsa
97820d12b7SJiri Olsa /*
988812ad41SAlexey Budankov * bitmap_free - Free bitmap
998812ad41SAlexey Budankov * @bitmap: pointer to bitmap
1008812ad41SAlexey Budankov */
bitmap_free(unsigned long * bitmap)1018812ad41SAlexey Budankov static inline void bitmap_free(unsigned long *bitmap)
1028812ad41SAlexey Budankov {
1038812ad41SAlexey Budankov free(bitmap);
1048812ad41SAlexey Budankov }
1058812ad41SAlexey Budankov
1068812ad41SAlexey Budankov /*
107820d12b7SJiri Olsa * bitmap_scnprintf - print bitmap list into buffer
108820d12b7SJiri Olsa * @bitmap: bitmap
109820d12b7SJiri Olsa * @nbits: size of bitmap
110820d12b7SJiri Olsa * @buf: buffer to store output
111820d12b7SJiri Olsa * @size: size of @buf
112820d12b7SJiri Olsa */
113e5b9252dSYury Norov size_t bitmap_scnprintf(unsigned long *bitmap, unsigned int nbits,
114820d12b7SJiri Olsa char *buf, size_t size);
115820d12b7SJiri Olsa
116741c74f5SJiri Olsa /**
117741c74f5SJiri Olsa * bitmap_and - Do logical and on bitmaps
118741c74f5SJiri Olsa * @dst: resulting bitmap
119741c74f5SJiri Olsa * @src1: operand 1
120741c74f5SJiri Olsa * @src2: operand 2
121741c74f5SJiri Olsa * @nbits: size of bitmap
122741c74f5SJiri Olsa */
bitmap_and(unsigned long * dst,const unsigned long * src1,const unsigned long * src2,unsigned int nbits)123e2863a78SYury Norov static inline bool bitmap_and(unsigned long *dst, const unsigned long *src1,
124741c74f5SJiri Olsa const unsigned long *src2, unsigned int nbits)
125741c74f5SJiri Olsa {
126741c74f5SJiri Olsa if (small_const_nbits(nbits))
127741c74f5SJiri Olsa return (*dst = *src1 & *src2 & BITMAP_LAST_WORD_MASK(nbits)) != 0;
128741c74f5SJiri Olsa return __bitmap_and(dst, src1, src2, nbits);
129741c74f5SJiri Olsa }
130741c74f5SJiri Olsa
1318812ad41SAlexey Budankov #ifdef __LITTLE_ENDIAN
1328812ad41SAlexey Budankov #define BITMAP_MEM_ALIGNMENT 8
1338812ad41SAlexey Budankov #else
1348812ad41SAlexey Budankov #define BITMAP_MEM_ALIGNMENT (8 * sizeof(unsigned long))
1358812ad41SAlexey Budankov #endif
1368812ad41SAlexey Budankov #define BITMAP_MEM_MASK (BITMAP_MEM_ALIGNMENT - 1)
1378812ad41SAlexey Budankov
bitmap_equal(const unsigned long * src1,const unsigned long * src2,unsigned int nbits)138005f1700SKees Cook static inline bool bitmap_equal(const unsigned long *src1,
1398812ad41SAlexey Budankov const unsigned long *src2, unsigned int nbits)
1408812ad41SAlexey Budankov {
1418812ad41SAlexey Budankov if (small_const_nbits(nbits))
1428812ad41SAlexey Budankov return !((*src1 ^ *src2) & BITMAP_LAST_WORD_MASK(nbits));
1438812ad41SAlexey Budankov if (__builtin_constant_p(nbits & BITMAP_MEM_MASK) &&
1448812ad41SAlexey Budankov IS_ALIGNED(nbits, BITMAP_MEM_ALIGNMENT))
1458812ad41SAlexey Budankov return !memcmp(src1, src2, nbits / 8);
1468812ad41SAlexey Budankov return __bitmap_equal(src1, src2, nbits);
1478812ad41SAlexey Budankov }
1488812ad41SAlexey Budankov
bitmap_intersects(const unsigned long * src1,const unsigned long * src2,unsigned int nbits)149005f1700SKees Cook static inline bool bitmap_intersects(const unsigned long *src1,
150005f1700SKees Cook const unsigned long *src2,
151005f1700SKees Cook unsigned int nbits)
152f20510d5SAlexey Bayduraev {
153f20510d5SAlexey Bayduraev if (small_const_nbits(nbits))
154f20510d5SAlexey Bayduraev return ((*src1 & *src2) & BITMAP_LAST_WORD_MASK(nbits)) != 0;
155f20510d5SAlexey Bayduraev else
156f20510d5SAlexey Bayduraev return __bitmap_intersects(src1, src2, nbits);
157f20510d5SAlexey Bayduraev }
158f20510d5SAlexey Bayduraev
bitmap_set(unsigned long * map,unsigned int start,unsigned int nbits)159*82114e45SWei Yang static inline void bitmap_set(unsigned long *map, unsigned int start, unsigned int nbits)
160*82114e45SWei Yang {
161*82114e45SWei Yang if (__builtin_constant_p(nbits) && nbits == 1)
162*82114e45SWei Yang __set_bit(start, map);
163*82114e45SWei Yang else if (small_const_nbits(start + nbits))
164*82114e45SWei Yang *map |= GENMASK(start + nbits - 1, start);
165*82114e45SWei Yang else if (__builtin_constant_p(start & BITMAP_MEM_MASK) &&
166*82114e45SWei Yang IS_ALIGNED(start, BITMAP_MEM_ALIGNMENT) &&
167*82114e45SWei Yang __builtin_constant_p(nbits & BITMAP_MEM_MASK) &&
168*82114e45SWei Yang IS_ALIGNED(nbits, BITMAP_MEM_ALIGNMENT))
169*82114e45SWei Yang memset((char *)map + start / 8, 0xff, nbits / 8);
170*82114e45SWei Yang else
171*82114e45SWei Yang __bitmap_set(map, start, nbits);
172*82114e45SWei Yang }
173*82114e45SWei Yang
bitmap_clear(unsigned long * map,unsigned int start,unsigned int nbits)174692a68eeSWei Yang static inline void bitmap_clear(unsigned long *map, unsigned int start,
175692a68eeSWei Yang unsigned int nbits)
176692a68eeSWei Yang {
177692a68eeSWei Yang if (__builtin_constant_p(nbits) && nbits == 1)
178692a68eeSWei Yang __clear_bit(start, map);
179692a68eeSWei Yang else if (small_const_nbits(start + nbits))
180692a68eeSWei Yang *map &= ~GENMASK(start + nbits - 1, start);
181692a68eeSWei Yang else if (__builtin_constant_p(start & BITMAP_MEM_MASK) &&
182692a68eeSWei Yang IS_ALIGNED(start, BITMAP_MEM_ALIGNMENT) &&
183692a68eeSWei Yang __builtin_constant_p(nbits & BITMAP_MEM_MASK) &&
184692a68eeSWei Yang IS_ALIGNED(nbits, BITMAP_MEM_ALIGNMENT))
185692a68eeSWei Yang memset((char *)map + start / 8, 0, nbits / 8);
186692a68eeSWei Yang else
187692a68eeSWei Yang __bitmap_clear(map, start, nbits);
188692a68eeSWei Yang }
1894ade0818SYury Norov #endif /* _TOOLS_LINUX_BITMAP_H */
190