Commit 30544ed5 authored by Andy Shevchenko's avatar Andy Shevchenko Committed by Linus Torvalds

lib/bitmap: introduce bitmap_replace() helper

In some drivers we want to have a single operation over bitmap which is
an equivalent to:

	*dst = (*old & ~(*mask)) | (*new & *mask)

Introduce bitmap_replace() helper for this.

Link: http://lkml.kernel.org/r/20191022172922.61232-8-andriy.shevchenko@linux.intel.comSigned-off-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Cc: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Cc: Marek Vasut <marek.vasut+renesas@gmail.com>
Cc: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
Cc: William Breathitt Gray <vilhelm.gray@gmail.com>
Cc: Yury Norov <yury.norov@gmail.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 780ff33b
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
* bitmap_find_next_zero_area_off(buf, len, pos, n, mask) as above * bitmap_find_next_zero_area_off(buf, len, pos, n, mask) as above
* bitmap_shift_right(dst, src, n, nbits) *dst = *src >> n * bitmap_shift_right(dst, src, n, nbits) *dst = *src >> n
* bitmap_shift_left(dst, src, n, nbits) *dst = *src << n * bitmap_shift_left(dst, src, n, nbits) *dst = *src << n
* bitmap_replace(dst, old, new, mask, nbits) *dst = (*old & ~(*mask)) | (*new & *mask)
* bitmap_remap(dst, src, old, new, nbits) *dst = map(old, new)(src) * bitmap_remap(dst, src, old, new, nbits) *dst = map(old, new)(src)
* bitmap_bitremap(oldbit, old, new, nbits) newbit = map(old, new)(oldbit) * bitmap_bitremap(oldbit, old, new, nbits) newbit = map(old, new)(oldbit)
* bitmap_onto(dst, orig, relmap, nbits) *dst = orig relative to relmap * bitmap_onto(dst, orig, relmap, nbits) *dst = orig relative to relmap
...@@ -140,6 +141,9 @@ extern void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1, ...@@ -140,6 +141,9 @@ extern void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
const unsigned long *bitmap2, unsigned int nbits); const unsigned long *bitmap2, unsigned int nbits);
extern int __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1, extern int __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
const unsigned long *bitmap2, unsigned int nbits); const unsigned long *bitmap2, unsigned int nbits);
extern void __bitmap_replace(unsigned long *dst,
const unsigned long *old, const unsigned long *new,
const unsigned long *mask, unsigned int nbits);
extern int __bitmap_intersects(const unsigned long *bitmap1, extern int __bitmap_intersects(const unsigned long *bitmap1,
const unsigned long *bitmap2, unsigned int nbits); const unsigned long *bitmap2, unsigned int nbits);
extern int __bitmap_subset(const unsigned long *bitmap1, extern int __bitmap_subset(const unsigned long *bitmap1,
...@@ -434,6 +438,18 @@ static inline void bitmap_shift_left(unsigned long *dst, const unsigned long *sr ...@@ -434,6 +438,18 @@ static inline void bitmap_shift_left(unsigned long *dst, const unsigned long *sr
__bitmap_shift_left(dst, src, shift, nbits); __bitmap_shift_left(dst, src, shift, nbits);
} }
static inline void bitmap_replace(unsigned long *dst,
const unsigned long *old,
const unsigned long *new,
const unsigned long *mask,
unsigned int nbits)
{
if (small_const_nbits(nbits))
*dst = (*old & ~(*mask)) | (*new & *mask);
else
__bitmap_replace(dst, old, new, mask, nbits);
}
static inline int bitmap_parse(const char *buf, unsigned int buflen, static inline int bitmap_parse(const char *buf, unsigned int buflen,
unsigned long *maskp, int nmaskbits) unsigned long *maskp, int nmaskbits)
{ {
......
...@@ -222,6 +222,18 @@ int __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1, ...@@ -222,6 +222,18 @@ int __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
} }
EXPORT_SYMBOL(__bitmap_andnot); EXPORT_SYMBOL(__bitmap_andnot);
void __bitmap_replace(unsigned long *dst,
const unsigned long *old, const unsigned long *new,
const unsigned long *mask, unsigned int nbits)
{
unsigned int k;
unsigned int nr = BITS_TO_LONGS(nbits);
for (k = 0; k < nr; k++)
dst[k] = (old[k] & ~mask[k]) | (new[k] & mask[k]);
}
EXPORT_SYMBOL(__bitmap_replace);
int __bitmap_intersects(const unsigned long *bitmap1, int __bitmap_intersects(const unsigned long *bitmap1,
const unsigned long *bitmap2, unsigned int bits) const unsigned long *bitmap2, unsigned int bits)
{ {
......
...@@ -42,6 +42,19 @@ static const unsigned long exp2[] __initconst = { ...@@ -42,6 +42,19 @@ static const unsigned long exp2[] __initconst = {
BITMAP_FROM_U64(0xffffffff77777777ULL), BITMAP_FROM_U64(0xffffffff77777777ULL),
}; };
/* Fibonacci sequence */
static const unsigned long exp2_to_exp3_mask[] __initconst = {
BITMAP_FROM_U64(0x008000020020212eULL),
};
/* exp3_0_1 = (exp2[0] & ~exp2_to_exp3_mask) | (exp2[1] & exp2_to_exp3_mask) */
static const unsigned long exp3_0_1[] __initconst = {
BITMAP_FROM_U64(0x33b3333311313137ULL),
};
/* exp3_1_0 = (exp2[1] & ~exp2_to_exp3_mask) | (exp2[0] & exp2_to_exp3_mask) */
static const unsigned long exp3_1_0[] __initconst = {
BITMAP_FROM_U64(0xff7fffff77575751ULL),
};
static bool __init static bool __init
__check_eq_uint(const char *srcfile, unsigned int line, __check_eq_uint(const char *srcfile, unsigned int line,
const unsigned int exp_uint, unsigned int x) const unsigned int exp_uint, unsigned int x)
...@@ -257,6 +270,30 @@ static void __init test_copy(void) ...@@ -257,6 +270,30 @@ static void __init test_copy(void)
expect_eq_pbl("0-108,128-1023", bmap2, 1024); expect_eq_pbl("0-108,128-1023", bmap2, 1024);
} }
#define EXP2_IN_BITS (sizeof(exp2) * 8)
static void __init test_replace(void)
{
unsigned int nbits = 64;
DECLARE_BITMAP(bmap, 1024);
bitmap_zero(bmap, 1024);
bitmap_replace(bmap, &exp2[0], &exp2[1], exp2_to_exp3_mask, nbits);
expect_eq_bitmap(bmap, exp3_0_1, nbits);
bitmap_zero(bmap, 1024);
bitmap_replace(bmap, &exp2[1], &exp2[0], exp2_to_exp3_mask, nbits);
expect_eq_bitmap(bmap, exp3_1_0, nbits);
bitmap_fill(bmap, 1024);
bitmap_replace(bmap, &exp2[0], &exp2[1], exp2_to_exp3_mask, nbits);
expect_eq_bitmap(bmap, exp3_0_1, nbits);
bitmap_fill(bmap, 1024);
bitmap_replace(bmap, &exp2[1], &exp2[0], exp2_to_exp3_mask, nbits);
expect_eq_bitmap(bmap, exp3_1_0, nbits);
}
#define PARSE_TIME 0x1 #define PARSE_TIME 0x1
struct test_bitmap_parselist{ struct test_bitmap_parselist{
...@@ -476,6 +513,7 @@ static void __init selftest(void) ...@@ -476,6 +513,7 @@ static void __init selftest(void)
test_zero_clear(); test_zero_clear();
test_fill_set(); test_fill_set();
test_copy(); test_copy();
test_replace();
test_bitmap_arr32(); test_bitmap_arr32();
test_bitmap_parselist(); test_bitmap_parselist();
test_bitmap_parselist_user(); test_bitmap_parselist_user();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment