@@ -80,4 +80,18 @@ extern unsigned long find_first_zero_bit(const unsigned long *addr,
#endif /* CONFIG_GENERIC_FIND_FIRST_BIT */
+unsigned long bitmap_get_value8(const unsigned long *const bitmap,
+ const unsigned int size,
+ const unsigned int start);
+
+void bitmap_set_value8(unsigned long *const bitmap, const unsigned int size,
+ const unsigned long value, const unsigned int start);
+
+unsigned int find_next_clump8(unsigned long *const clump,
+ const unsigned long *const addr,
+ unsigned int offset, const unsigned int size);
+
+#define find_first_clump8(clump, bits, size) \
+ find_next_clump8((clump), (bits), 0, (size))
+
#endif /*_ASM_GENERIC_BITOPS_FIND_H_ */
@@ -40,6 +40,11 @@ extern unsigned long __sw_hweight64(__u64 w);
(bit) < (size); \
(bit) = find_next_zero_bit((addr), (size), (bit) + 1))
+#define for_each_set_clump8(start, clump, bits, size) \
+ for ((start) = find_first_clump8(&(clump), (bits), (size)); \
+ (start) < (size); \
+ (start) = find_next_clump8(&(clump), (bits), (start) + 8, (size)))
+
static inline int get_bitmask_order(unsigned int count)
{
int order;
@@ -218,3 +218,84 @@ EXPORT_SYMBOL(find_next_bit_le);
#endif
#endif /* __BIG_ENDIAN */
+
+/**
+ * bitmap_get_value8 - get an 8-bit value within a memory region
+ * @bitmap: address to the bitmap memory region
+ * @size: bitmap size in number of bits
+ * @start: bit offset of the 8-bit value
+ *
+ * Returns the 8-bit value located at the @start bit offset within the @bitmap
+ * memory region.
+ */
+unsigned long bitmap_get_value8(const unsigned long *const bitmap,
+ const unsigned int size,
+ const unsigned int start)
+{
+ const size_t index = BIT_WORD(start);
+ const unsigned int offset = start % BITS_PER_LONG;
+ const unsigned int low_width = (offset + 8 > BITS_PER_LONG) ?
+ BITS_PER_LONG - offset : 8;
+ const unsigned long low = bitmap[index] >> offset;
+ const unsigned long high = (low_width < 8 && start + 8 <= size) ?
+ bitmap[index + 1] << low_width : 0;
+
+ return (low | high) & 0xFF;
+}
+EXPORT_SYMBOL(bitmap_get_value8);
+
+/**
+ * bitmap_set_value8 - set an 8-bit value within a memory region
+ * @bitmap: address to the bitmap memory region
+ * @size: bitmap size in number of bits
+ * @value: the 8-bit value; values wider than 8 bits may clobber bitmap
+ * @start: bit offset of the 8-bit value
+ */
+void bitmap_set_value8(unsigned long *const bitmap, const unsigned int size,
+ const unsigned long value, const unsigned int start)
+{
+ const size_t index = BIT_WORD(start);
+ const unsigned int offset = start % BITS_PER_LONG;
+ const unsigned int low_width = (offset + 8 > BITS_PER_LONG) ?
+ BITS_PER_LONG - offset : 8;
+ const unsigned long low_mask = GENMASK(offset + low_width - 1, offset);
+ const unsigned int high_width = 8 - low_width;
+ const unsigned long high_mask = GENMASK(high_width - 1, 0);
+
+ /* set lower portion */
+ bitmap[index] &= ~low_mask;
+ bitmap[index] |= value << offset;
+
+ /* set higher portion if space available in bitmap */
+ if (high_width && start + 8 <= size) {
+ bitmap[index + 1] &= ~high_mask;
+ bitmap[index + 1] |= value >> low_width;
+ }
+}
+EXPORT_SYMBOL(bitmap_set_value8);
+
+/**
+ * find_next_clump8 - find next 8-bit clump with set bits in a memory region
+ * @clump: location to store copy of found clump
+ * @addr: address to base the search on
+ * @offset: bit offset at which to start searching
+ * @size: bitmap size in number of bits
+ *
+ * Returns the bit offset for the next set clump; the found clump value is
+ * copied to the location pointed by @clump. If no bits are set, returns @size.
+ */
+unsigned int find_next_clump8(unsigned long *const clump,
+ const unsigned long *const addr,
+ unsigned int offset, const unsigned int size)
+{
+ for (; offset < size; offset += 8) {
+ *clump = bitmap_get_value8(addr, size, offset);
+ if (!*clump)
+ continue;
+
+ return offset;
+ }
+
+ return size;
+}
+EXPORT_SYMBOL(find_next_clump8);