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