xref: /freebsd/sys/compat/linuxkpi/common/include/linux/bitmap.h (revision dbca442414191a43f334435b7910b63cb2777d53)
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
bitmap_zero(unsigned long * addr,const unsigned int size)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
bitmap_fill(unsigned long * addr,const unsigned int size)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
bitmap_full(unsigned long * addr,const unsigned int size)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
bitmap_empty(unsigned long * addr,const unsigned int size)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
bitmap_set(unsigned long * map,unsigned int start,int nr)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
bitmap_clear(unsigned long * map,unsigned int start,int nr)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
bitmap_find_next_zero_area_off(const unsigned long * map,const unsigned int size,unsigned int start,unsigned int nr,unsigned int align_mask,unsigned int align_offset)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
bitmap_find_next_zero_area(const unsigned long * map,const unsigned int size,unsigned int start,unsigned int nr,unsigned int align_mask)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
bitmap_find_free_region(unsigned long * bitmap,int bits,int order)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
bitmap_allocate_region(unsigned long * bitmap,int pos,int order)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
bitmap_release_region(unsigned long * bitmap,int pos,int order)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
bitmap_weight(unsigned long * addr,const unsigned int size)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
bitmap_equal(const unsigned long * pa,const unsigned long * pb,unsigned size)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
bitmap_subset(const unsigned long * pa,const unsigned long * pb,unsigned size)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
bitmap_intersects(const unsigned long * pa,const unsigned long * pb,unsigned size)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
bitmap_complement(unsigned long * dst,const unsigned long * src,const unsigned int size)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
bitmap_copy(unsigned long * dst,const unsigned long * src,const unsigned int size)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
bitmap_to_arr32(uint32_t * dst,const unsigned long * src,unsigned int size)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
bitmap_from_arr32(unsigned long * dst,const uint32_t * src,unsigned int size)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
bitmap_or(unsigned long * dst,const unsigned long * src1,const unsigned long * src2,const unsigned int size)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
bitmap_and(unsigned long * dst,const unsigned long * src1,const unsigned long * src2,const unsigned int size)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
bitmap_andnot(unsigned long * dst,const unsigned long * src1,const unsigned long * src2,const unsigned int size)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
bitmap_xor(unsigned long * dst,const unsigned long * src1,const unsigned long * src2,const unsigned int size)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
bitmap_shift_right(unsigned long * dst,const unsigned long * src,unsigned int shift,unsigned int size)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 *
bitmap_alloc(unsigned int size,gfp_t flags)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 *
bitmap_zalloc(unsigned int size,gfp_t flags)439  bitmap_zalloc(unsigned int size, gfp_t flags)
440  {
441  	return (bitmap_alloc(size, flags | __GFP_ZERO));
442  }
443  
444  static inline void
bitmap_free(const unsigned long * bitmap)445  bitmap_free(const unsigned long *bitmap)
446  {
447  	kfree(bitmap);
448  }
449  
450  #endif					/* _LINUXKPI_LINUX_BITMAP_H_ */
451