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  * $FreeBSD$
27  */
28 
29 #ifndef _LINUXKPI_LINUX_BITMAP_H_
30 #define	_LINUXKPI_LINUX_BITMAP_H_
31 
32 #include <linux/bitops.h>
33 #include <linux/slab.h>
34 
35 static inline void
36 bitmap_zero(unsigned long *addr, const unsigned int size)
37 {
38 	memset(addr, 0, BITS_TO_LONGS(size) * sizeof(long));
39 }
40 
41 static inline void
42 bitmap_fill(unsigned long *addr, const unsigned int size)
43 {
44 	const unsigned int tail = size & (BITS_PER_LONG - 1);
45 
46 	memset(addr, 0xff, BIT_WORD(size) * sizeof(long));
47 
48 	if (tail)
49 		addr[BIT_WORD(size)] = BITMAP_LAST_WORD_MASK(tail);
50 }
51 
52 static inline int
53 bitmap_full(unsigned long *addr, const unsigned int size)
54 {
55 	const unsigned int end = BIT_WORD(size);
56 	const unsigned int tail = size & (BITS_PER_LONG - 1);
57 	unsigned int i;
58 
59 	for (i = 0; i != end; i++) {
60 		if (addr[i] != ~0UL)
61 			return (0);
62 	}
63 
64 	if (tail) {
65 		const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
66 
67 		if ((addr[end] & mask) != mask)
68 			return (0);
69 	}
70 	return (1);
71 }
72 
73 static inline int
74 bitmap_empty(unsigned long *addr, const unsigned int size)
75 {
76 	const unsigned int end = BIT_WORD(size);
77 	const unsigned int tail = size & (BITS_PER_LONG - 1);
78 	unsigned int i;
79 
80 	for (i = 0; i != end; i++) {
81 		if (addr[i] != 0)
82 			return (0);
83 	}
84 
85 	if (tail) {
86 		const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
87 
88 		if ((addr[end] & mask) != 0)
89 			return (0);
90 	}
91 	return (1);
92 }
93 
94 static inline void
95 bitmap_set(unsigned long *map, unsigned int start, int nr)
96 {
97 	const unsigned int size = start + nr;
98 	int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG);
99 	unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start);
100 
101 	map += BIT_WORD(start);
102 
103 	while (nr - bits_to_set >= 0) {
104 		*map |= mask_to_set;
105 		nr -= bits_to_set;
106 		bits_to_set = BITS_PER_LONG;
107 		mask_to_set = ~0UL;
108 		map++;
109 	}
110 
111 	if (nr) {
112 		mask_to_set &= BITMAP_LAST_WORD_MASK(size);
113 		*map |= mask_to_set;
114 	}
115 }
116 
117 static inline void
118 bitmap_clear(unsigned long *map, unsigned int start, int nr)
119 {
120 	const unsigned int size = start + nr;
121 	int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG);
122 	unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start);
123 
124 	map += BIT_WORD(start);
125 
126 	while (nr - bits_to_clear >= 0) {
127 		*map &= ~mask_to_clear;
128 		nr -= bits_to_clear;
129 		bits_to_clear = BITS_PER_LONG;
130 		mask_to_clear = ~0UL;
131 		map++;
132 	}
133 
134 	if (nr) {
135 		mask_to_clear &= BITMAP_LAST_WORD_MASK(size);
136 		*map &= ~mask_to_clear;
137 	}
138 }
139 
140 static inline unsigned int
141 bitmap_find_next_zero_area_off(const unsigned long *map,
142     const unsigned int size, unsigned int start,
143     unsigned int nr, unsigned int align_mask,
144     unsigned int align_offset)
145 {
146 	unsigned int index;
147 	unsigned int end;
148 	unsigned int i;
149 
150 retry:
151 	index = find_next_zero_bit(map, size, start);
152 
153 	index = (((index + align_offset) + align_mask) & ~align_mask) - align_offset;
154 
155 	end = index + nr;
156 	if (end > size)
157 		return (end);
158 
159 	i = find_next_bit(map, end, index);
160 	if (i < end) {
161 		start = i + 1;
162 		goto retry;
163 	}
164 	return (index);
165 }
166 
167 static inline unsigned int
168 bitmap_find_next_zero_area(const unsigned long *map,
169     const unsigned int size, unsigned int start,
170     unsigned int nr, unsigned int align_mask)
171 {
172 	return (bitmap_find_next_zero_area_off(map, size,
173 	    start, nr, align_mask, 0));
174 }
175 
176 static inline int
177 bitmap_find_free_region(unsigned long *bitmap, int bits, int order)
178 {
179 	int pos;
180 	int end;
181 
182 	for (pos = 0; (end = pos + (1 << order)) <= bits; pos = end) {
183 		if (!linux_reg_op(bitmap, pos, order, REG_OP_ISFREE))
184 			continue;
185 		linux_reg_op(bitmap, pos, order, REG_OP_ALLOC);
186 		return (pos);
187 	}
188 	return (-ENOMEM);
189 }
190 
191 static inline int
192 bitmap_allocate_region(unsigned long *bitmap, int pos, int order)
193 {
194 	if (!linux_reg_op(bitmap, pos, order, REG_OP_ISFREE))
195 		return (-EBUSY);
196 	linux_reg_op(bitmap, pos, order, REG_OP_ALLOC);
197 	return (0);
198 }
199 
200 static inline void
201 bitmap_release_region(unsigned long *bitmap, int pos, int order)
202 {
203 	linux_reg_op(bitmap, pos, order, REG_OP_RELEASE);
204 }
205 
206 static inline unsigned int
207 bitmap_weight(unsigned long *addr, const unsigned int size)
208 {
209 	const unsigned int end = BIT_WORD(size);
210 	const unsigned int tail = size & (BITS_PER_LONG - 1);
211 	unsigned int retval = 0;
212 	unsigned int i;
213 
214 	for (i = 0; i != end; i++)
215 		retval += hweight_long(addr[i]);
216 
217 	if (tail) {
218 		const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
219 
220 		retval += hweight_long(addr[end] & mask);
221 	}
222 	return (retval);
223 }
224 
225 static inline int
226 bitmap_equal(const unsigned long *pa,
227     const unsigned long *pb, unsigned size)
228 {
229 	const unsigned int end = BIT_WORD(size);
230 	const unsigned int tail = size & (BITS_PER_LONG - 1);
231 	unsigned int i;
232 
233 	for (i = 0; i != end; i++) {
234 		if (pa[i] != pb[i])
235 			return (0);
236 	}
237 
238 	if (tail) {
239 		const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
240 
241 		if ((pa[end] ^ pb[end]) & mask)
242 			return (0);
243 	}
244 	return (1);
245 }
246 
247 static inline int
248 bitmap_subset(const unsigned long *pa,
249     const unsigned long *pb, unsigned size)
250 {
251 	const unsigned end = BIT_WORD(size);
252 	const unsigned tail = size & (BITS_PER_LONG - 1);
253 	unsigned i;
254 
255 	for (i = 0; i != end; i++) {
256 		if (pa[i] & ~pb[i])
257 			return (0);
258 	}
259 
260 	if (tail) {
261 		const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
262 
263 		if (pa[end] & ~pb[end] & mask)
264 			return (0);
265 	}
266 	return (1);
267 }
268 
269 static inline void
270 bitmap_complement(unsigned long *dst, const unsigned long *src,
271     const unsigned int size)
272 {
273 	const unsigned int end = BITS_TO_LONGS(size);
274 	unsigned int i;
275 
276 	for (i = 0; i != end; i++)
277 		dst[i] = ~src[i];
278 }
279 
280 static inline void
281 bitmap_copy(unsigned long *dst, const unsigned long *src,
282     const unsigned int size)
283 {
284 	const unsigned int end = BITS_TO_LONGS(size);
285 	unsigned int i;
286 
287 	for (i = 0; i != end; i++)
288 		dst[i] = src[i];
289 }
290 
291 static inline void
292 bitmap_to_arr32(uint32_t *dst, const unsigned long *src, unsigned int size)
293 {
294 	const unsigned int end = howmany(size, 32);
295 
296 #ifdef __LP64__
297 	unsigned int i = 0;
298 	while (i < end) {
299 		dst[i++] = (uint32_t)(*src & UINT_MAX);
300 		if (i < end)
301 			dst[i++] = (uint32_t)(*src >> 32);
302 		src++;
303 	}
304 #else
305 	bitmap_copy((unsigned long *)dst, src, size);
306 #endif
307 	if ((size % 32) != 0) /* Linux uses BITS_PER_LONG. Seems to be a bug */
308 		dst[end - 1] &= (uint32_t)(UINT_MAX >> (32 - (size % 32)));
309 }
310 
311 static inline void
312 bitmap_or(unsigned long *dst, const unsigned long *src1,
313     const unsigned long *src2, const unsigned int size)
314 {
315 	const unsigned int end = BITS_TO_LONGS(size);
316 	unsigned int i;
317 
318 	for (i = 0; i != end; i++)
319 		dst[i] = src1[i] | src2[i];
320 }
321 
322 static inline void
323 bitmap_and(unsigned long *dst, const unsigned long *src1,
324     const unsigned long *src2, const unsigned int size)
325 {
326 	const unsigned int end = BITS_TO_LONGS(size);
327 	unsigned int i;
328 
329 	for (i = 0; i != end; i++)
330 		dst[i] = src1[i] & src2[i];
331 }
332 
333 static inline void
334 bitmap_andnot(unsigned long *dst, const unsigned long *src1,
335     const unsigned long *src2, const unsigned int size)
336 {
337 	const unsigned int end = BITS_TO_LONGS(size);
338 	unsigned int i;
339 
340 	for (i = 0; i != end; i++)
341 		dst[i] = src1[i] & ~src2[i];
342 }
343 
344 static inline void
345 bitmap_xor(unsigned long *dst, const unsigned long *src1,
346     const unsigned long *src2, const unsigned int size)
347 {
348 	const unsigned int end = BITS_TO_LONGS(size);
349 	unsigned int i;
350 
351 	for (i = 0; i != end; i++)
352 		dst[i] = src1[i] ^ src2[i];
353 }
354 
355 static inline unsigned long *
356 bitmap_alloc(unsigned int size, gfp_t flags)
357 {
358 	return (kmalloc_array(BITS_TO_LONGS(size),
359 	    sizeof(unsigned long), flags));
360 }
361 
362 static inline unsigned long *
363 bitmap_zalloc(unsigned int size, gfp_t flags)
364 {
365 	return (bitmap_alloc(size, flags | __GFP_ZERO));
366 }
367 
368 static inline void
369 bitmap_free(const unsigned long *bitmap)
370 {
371 	kfree(bitmap);
372 }
373 
374 #endif					/* _LINUXKPI_LINUX_BITMAP_H_ */
375