[U-Boot,2/8] bitmaps: import for_each_set_bit() macro
diff mbox series

Message ID 20191001115636.21052-3-vigneshr@ti.com
State Accepted
Commit c93e305af72a344c66f467899b6277b4d3d94db9
Delegated to: Lukasz Majewski
Headers show
Series
  • usb: Add support for Cadence USB controller driver
Related show

Commit Message

Vignesh Raghavendra Oct. 1, 2019, 11:56 a.m. UTC
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>
---
 include/linux/bitmap.h | 61 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)

Patch
diff mbox series

diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h
index 4a54ae050912..fbbb67c8b24e 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 */