xref: /freebsd/sys/compat/linuxkpi/common/include/linux/bitmap.h (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
1 /*
2  * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice unmodified, this list of conditions, and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #ifndef _LINUXKPI_LINUX_BITMAP_H_
28 #define	_LINUXKPI_LINUX_BITMAP_H_
29 
30 #include <linux/bitops.h>
31 #include <linux/slab.h>
32 
33 static inline void
34 bitmap_zero(unsigned long *addr, const unsigned int size)
35 {
36 	memset(addr, 0, BITS_TO_LONGS(size) * sizeof(long));
37 }
38 
39 static inline void
40 bitmap_fill(unsigned long *addr, const unsigned int size)
41 {
42 	const unsigned int tail = size & (BITS_PER_LONG - 1);
43 
44 	memset(addr, 0xff, BIT_WORD(size) * sizeof(long));
45 
46 	if (tail)
47 		addr[BIT_WORD(size)] = BITMAP_LAST_WORD_MASK(tail);
48 }
49 
50 static inline int
51 bitmap_full(unsigned long *addr, const unsigned int size)
52 {
53 	const unsigned int end = BIT_WORD(size);
54 	const unsigned int tail = size & (BITS_PER_LONG - 1);
55 	unsigned int i;
56 
57 	for (i = 0; i != end; i++) {
58 		if (addr[i] != ~0UL)
59 			return (0);
60 	}
61 
62 	if (tail) {
63 		const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
64 
65 		if ((addr[end] & mask) != mask)
66 			return (0);
67 	}
68 	return (1);
69 }
70 
71 static inline int
72 bitmap_empty(unsigned long *addr, const unsigned int size)
73 {
74 	const unsigned int end = BIT_WORD(size);
75 	const unsigned int tail = size & (BITS_PER_LONG - 1);
76 	unsigned int i;
77 
78 	for (i = 0; i != end; i++) {
79 		if (addr[i] != 0)
80 			return (0);
81 	}
82 
83 	if (tail) {
84 		const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
85 
86 		if ((addr[end] & mask) != 0)
87 			return (0);
88 	}
89 	return (1);
90 }
91 
92 static inline void
93 bitmap_set(unsigned long *map, unsigned int start, int nr)
94 {
95 	const unsigned int size = start + nr;
96 	int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG);
97 	unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start);
98 
99 	map += BIT_WORD(start);
100 
101 	while (nr - bits_to_set >= 0) {
102 		*map |= mask_to_set;
103 		nr -= bits_to_set;
104 		bits_to_set = BITS_PER_LONG;
105 		mask_to_set = ~0UL;
106 		map++;
107 	}
108 
109 	if (nr) {
110 		mask_to_set &= BITMAP_LAST_WORD_MASK(size);
111 		*map |= mask_to_set;
112 	}
113 }
114 
115 static inline void
116 bitmap_clear(unsigned long *map, unsigned int start, int nr)
117 {
118 	const unsigned int size = start + nr;
119 	int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG);
120 	unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start);
121 
122 	map += BIT_WORD(start);
123 
124 	while (nr - bits_to_clear >= 0) {
125 		*map &= ~mask_to_clear;
126 		nr -= bits_to_clear;
127 		bits_to_clear = BITS_PER_LONG;
128 		mask_to_clear = ~0UL;
129 		map++;
130 	}
131 
132 	if (nr) {
133 		mask_to_clear &= BITMAP_LAST_WORD_MASK(size);
134 		*map &= ~mask_to_clear;
135 	}
136 }
137 
138 static inline unsigned int
139 bitmap_find_next_zero_area_off(const unsigned long *map,
140     const unsigned int size, unsigned int start,
141     unsigned int nr, unsigned int align_mask,
142     unsigned int align_offset)
143 {
144 	unsigned int index;
145 	unsigned int end;
146 	unsigned int i;
147 
148 retry:
149 	index = find_next_zero_bit(map, size, start);
150 
151 	index = (((index + align_offset) + align_mask) & ~align_mask) - align_offset;
152 
153 	end = index + nr;
154 	if (end > size)
155 		return (end);
156 
157 	i = find_next_bit(map, end, index);
158 	if (i < end) {
159 		start = i + 1;
160 		goto retry;
161 	}
162 	return (index);
163 }
164 
165 static inline unsigned int
166 bitmap_find_next_zero_area(const unsigned long *map,
167     const unsigned int size, unsigned int start,
168     unsigned int nr, unsigned int align_mask)
169 {
170 	return (bitmap_find_next_zero_area_off(map, size,
171 	    start, nr, align_mask, 0));
172 }
173 
174 static inline int
175 bitmap_find_free_region(unsigned long *bitmap, int bits, int order)
176 {
177 	int pos;
178 	int end;
179 
180 	for (pos = 0; (end = pos + (1 << order)) <= bits; pos = end) {
181 		if (!linux_reg_op(bitmap, pos, order, REG_OP_ISFREE))
182 			continue;
183 		linux_reg_op(bitmap, pos, order, REG_OP_ALLOC);
184 		return (pos);
185 	}
186 	return (-ENOMEM);
187 }
188 
189 static inline int
190 bitmap_allocate_region(unsigned long *bitmap, int pos, int order)
191 {
192 	if (!linux_reg_op(bitmap, pos, order, REG_OP_ISFREE))
193 		return (-EBUSY);
194 	linux_reg_op(bitmap, pos, order, REG_OP_ALLOC);
195 	return (0);
196 }
197 
198 static inline void
199 bitmap_release_region(unsigned long *bitmap, int pos, int order)
200 {
201 	linux_reg_op(bitmap, pos, order, REG_OP_RELEASE);
202 }
203 
204 static inline unsigned int
205 bitmap_weight(unsigned long *addr, const unsigned int size)
206 {
207 	const unsigned int end = BIT_WORD(size);
208 	const unsigned int tail = size & (BITS_PER_LONG - 1);
209 	unsigned int retval = 0;
210 	unsigned int i;
211 
212 	for (i = 0; i != end; i++)
213 		retval += hweight_long(addr[i]);
214 
215 	if (tail) {
216 		const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
217 
218 		retval += hweight_long(addr[end] & mask);
219 	}
220 	return (retval);
221 }
222 
223 static inline int
224 bitmap_equal(const unsigned long *pa,
225     const unsigned long *pb, unsigned size)
226 {
227 	const unsigned int end = BIT_WORD(size);
228 	const unsigned int tail = size & (BITS_PER_LONG - 1);
229 	unsigned int i;
230 
231 	for (i = 0; i != end; i++) {
232 		if (pa[i] != pb[i])
233 			return (0);
234 	}
235 
236 	if (tail) {
237 		const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
238 
239 		if ((pa[end] ^ pb[end]) & mask)
240 			return (0);
241 	}
242 	return (1);
243 }
244 
245 static inline int
246 bitmap_subset(const unsigned long *pa,
247     const unsigned long *pb, unsigned size)
248 {
249 	const unsigned end = BIT_WORD(size);
250 	const unsigned tail = size & (BITS_PER_LONG - 1);
251 	unsigned i;
252 
253 	for (i = 0; i != end; i++) {
254 		if (pa[i] & ~pb[i])
255 			return (0);
256 	}
257 
258 	if (tail) {
259 		const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
260 
261 		if (pa[end] & ~pb[end] & mask)
262 			return (0);
263 	}
264 	return (1);
265 }
266 
267 static inline bool
268 bitmap_intersects(const unsigned long *pa, const unsigned long *pb,
269     unsigned size)
270 {
271 	const unsigned end = BIT_WORD(size);
272 	const unsigned tail = size & (BITS_PER_LONG - 1);
273 	unsigned i;
274 
275 	for (i = 0; i != end; i++)
276 		if (pa[i] & pb[i])
277 			return (true);
278 
279 	if (tail) {
280 		 const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
281 
282 		if (pa[end] & pb[end] & mask)
283 			return (true);
284 	}
285 	return (false);
286 }
287 
288 static inline void
289 bitmap_complement(unsigned long *dst, const unsigned long *src,
290     const unsigned int size)
291 {
292 	const unsigned int end = BITS_TO_LONGS(size);
293 	unsigned int i;
294 
295 	for (i = 0; i != end; i++)
296 		dst[i] = ~src[i];
297 }
298 
299 static inline void
300 bitmap_copy(unsigned long *dst, const unsigned long *src,
301     const unsigned int size)
302 {
303 	const unsigned int end = BITS_TO_LONGS(size);
304 	unsigned int i;
305 
306 	for (i = 0; i != end; i++)
307 		dst[i] = src[i];
308 }
309 
310 static inline void
311 bitmap_to_arr32(uint32_t *dst, const unsigned long *src, unsigned int size)
312 {
313 	const unsigned int end = howmany(size, 32);
314 
315 #ifdef __LP64__
316 	unsigned int i = 0;
317 	while (i < end) {
318 		dst[i++] = (uint32_t)(*src & UINT_MAX);
319 		if (i < end)
320 			dst[i++] = (uint32_t)(*src >> 32);
321 		src++;
322 	}
323 #else
324 	bitmap_copy((unsigned long *)dst, src, size);
325 #endif
326 	if ((size % 32) != 0) /* Linux uses BITS_PER_LONG. Seems to be a bug */
327 		dst[end - 1] &= (uint32_t)(UINT_MAX >> (32 - (size % 32)));
328 }
329 
330 static inline void
331 bitmap_from_arr32(unsigned long *dst, const uint32_t *src,
332     unsigned int size)
333 {
334 	const unsigned int end = BIT_WORD(size);
335 	const unsigned int tail = size & (BITS_PER_LONG - 1);
336 
337 #ifdef __LP64__
338 	const unsigned int end32 = howmany(size, 32);
339 	unsigned int i = 0;
340 
341 	while (i < end32) {
342 		dst[i++/2] = (unsigned long) *(src++);
343 		if (i < end32)
344 			dst[i++/2] |= ((unsigned long) *(src++)) << 32;
345 	}
346 #else
347 	bitmap_copy(dst, (const unsigned long *)src, size);
348 #endif
349 	if ((size % BITS_PER_LONG) != 0)
350 		dst[end] &= BITMAP_LAST_WORD_MASK(tail);
351 }
352 
353 static inline void
354 bitmap_or(unsigned long *dst, const unsigned long *src1,
355     const unsigned long *src2, const unsigned int size)
356 {
357 	const unsigned int end = BITS_TO_LONGS(size);
358 	unsigned int i;
359 
360 	for (i = 0; i != end; i++)
361 		dst[i] = src1[i] | src2[i];
362 }
363 
364 static inline void
365 bitmap_and(unsigned long *dst, const unsigned long *src1,
366     const unsigned long *src2, const unsigned int size)
367 {
368 	const unsigned int end = BITS_TO_LONGS(size);
369 	unsigned int i;
370 
371 	for (i = 0; i != end; i++)
372 		dst[i] = src1[i] & src2[i];
373 }
374 
375 static inline void
376 bitmap_andnot(unsigned long *dst, const unsigned long *src1,
377     const unsigned long *src2, const unsigned int size)
378 {
379 	const unsigned int end = BITS_TO_LONGS(size);
380 	unsigned int i;
381 
382 	for (i = 0; i != end; i++)
383 		dst[i] = src1[i] & ~src2[i];
384 }
385 
386 static inline void
387 bitmap_xor(unsigned long *dst, const unsigned long *src1,
388     const unsigned long *src2, const unsigned int size)
389 {
390 	const unsigned int end = BITS_TO_LONGS(size);
391 	unsigned int i;
392 
393 	for (i = 0; i != end; i++)
394 		dst[i] = src1[i] ^ src2[i];
395 }
396 
397 static inline void
398 bitmap_shift_right(unsigned long *dst, const unsigned long *src,
399     unsigned int shift, unsigned int size)
400 {
401 	const unsigned int end = BITS_TO_LONGS(size);
402 	const unsigned int tail = size & (BITS_PER_LONG - 1);
403 	const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
404 	const unsigned int off = BIT_WORD(shift);
405 	const unsigned int rem = shift & (BITS_PER_LONG - 1);
406 	unsigned long left, right;
407 	unsigned int i, srcpos;
408 
409 	for (i = 0, srcpos = off; srcpos < end; i++, srcpos++) {
410 		right = src[srcpos];
411 		left = 0;
412 
413 		if (srcpos == end - 1)
414 			right &= mask;
415 
416 		if (rem != 0) {
417 			right >>= rem;
418 			if (srcpos + 1 < end) {
419 				left = src[srcpos + 1];
420 				if (srcpos + 1 == end - 1)
421 					left &= mask;
422 				left <<= (BITS_PER_LONG - rem);
423 			}
424 		}
425 		dst[i] = left | right;
426 	}
427 	if (off != 0)
428 		memset(dst + end - off, 0, off * sizeof(unsigned long));
429 }
430 
431 static inline unsigned long *
432 bitmap_alloc(unsigned int size, gfp_t flags)
433 {
434 	return (kmalloc_array(BITS_TO_LONGS(size),
435 	    sizeof(unsigned long), flags));
436 }
437 
438 static inline unsigned long *
439 bitmap_zalloc(unsigned int size, gfp_t flags)
440 {
441 	return (bitmap_alloc(size, flags | __GFP_ZERO));
442 }
443 
444 static inline void
445 bitmap_free(const unsigned long *bitmap)
446 {
447 	kfree(bitmap);
448 }
449 
450 #endif					/* _LINUXKPI_LINUX_BITMAP_H_ */
451