summaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
authorVignesh Raghavendra <vigneshr@ti.com>2019-10-01 17:26:30 +0530
committerMarek Vasut <marek.vasut+renesas@gmail.com>2019-11-07 00:24:59 +0100
commitc93e305af72a344c66f467899b6277b4d3d94db9 (patch)
treea6b38ce16896abf5d3b2084af79abc2b87a38f0c /include/linux
parentc37f594280aa3fc9d534420581f7db47ac843297 (diff)
bitmaps: import for_each_set_bit() macro
Import for_each_set_bit() and associated macros and functions from Linux. This is useful in parsing interrupt registers and take action on each bit that is set. Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/bitmap.h61
1 files changed, 61 insertions, 0 deletions
diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h
index 4a54ae0509..fbbb67c8b2 100644
--- a/include/linux/bitmap.h
+++ b/include/linux/bitmap.h
@@ -20,4 +20,65 @@ static inline void bitmap_zero(unsigned long *dst, int nbits)
}
}
+static inline unsigned long
+find_next_bit(const unsigned long *addr, unsigned long size,
+ unsigned long offset)
+{
+ const unsigned long *p = addr + BIT_WORD(offset);
+ unsigned long result = offset & ~(BITS_PER_LONG - 1);
+ unsigned long tmp;
+
+ if (offset >= size)
+ return size;
+ size -= result;
+ offset %= BITS_PER_LONG;
+ if (offset) {
+ tmp = *(p++);
+ tmp &= (~0UL << offset);
+ if (size < BITS_PER_LONG)
+ goto found_first;
+ if (tmp)
+ goto found_middle;
+ size -= BITS_PER_LONG;
+ result += BITS_PER_LONG;
+ }
+ while (size & ~(BITS_PER_LONG - 1)) {
+ tmp = *(p++);
+ if ((tmp))
+ goto found_middle;
+ result += BITS_PER_LONG;
+ size -= BITS_PER_LONG;
+ }
+ if (!size)
+ return result;
+ tmp = *p;
+
+found_first:
+ tmp &= (~0UL >> (BITS_PER_LONG - size));
+ if (tmp == 0UL) /* Are any bits set? */
+ return result + size; /* Nope. */
+found_middle:
+ return result + __ffs(tmp);
+}
+
+/*
+ * Find the first set bit in a memory region.
+ */
+static inline unsigned long find_first_bit(const unsigned long *addr, unsigned long size)
+{
+ unsigned long idx;
+
+ for (idx = 0; idx * BITS_PER_LONG < size; idx++) {
+ if (addr[idx])
+ return min(idx * BITS_PER_LONG + __ffs(addr[idx]), size);
+ }
+
+ return size;
+}
+
+#define for_each_set_bit(bit, addr, size) \
+ for ((bit) = find_first_bit((addr), (size)); \
+ (bit) < (size); \
+ (bit) = find_next_bit((addr), (size), (bit) + 1))
+
#endif /* __LINUX_BITMAP_H */