From: Yury Norov <yury.norov@gmail.com>
To: Andrew Lunn <andrew@lunn.ch>,
Heiner Kallweit <hkallweit1@gmail.com>,
Russell King <linux@armlinux.org.uk>,
Raju Rangoju <Raju.Rangoju@amd.com>,
Prashanth Kumar K R <PrashanthKumar.K.R@amd.com>,
Tony Nguyen <anthony.l.nguyen@intel.com>,
Przemek Kitszel <przemyslaw.kitszel@intel.com>,
Jian Shen <shenjian15@huawei.com>,
Jijie Shao <shaojijie@huawei.com>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
intel-wired-lan@lists.osuosl.org, linux-usb@vger.kernel.org
Cc: Yury Norov <ynorov@nvidia.com>, Yury Norov <yury.norov@gmail.com>,
Rasmus Villemoes <linux@rasmusvillemoes.dk>,
Andrew Morton <akpm@linux-foundation.org>
Subject: [PATCH 1/9] bitmap: add bitmap_and_and() and bitmap_and_andnot()
Date: Mon, 7 Sep 2026 17:54:30 -0400 [thread overview]
Message-ID: <20260907215439.409858-2-ynorov@nvidia.com> (raw)
In-Reply-To: <20260907215439.409858-1-ynorov@nvidia.com>
Add bitmap_and_and() and bitmap_and_andnot() to combine three bitmaps
in a single pass. Both helpers return whether the resulting bitmap is
non-empty.
Introduce BITMAP_OP() to share the word iteration with bitmap_and(),
and add tests for small constants, multiword bitmaps, aliases, tail
masking, empty results and zero-sized bitmaps.
Signed-off-by: Yury Norov <ynorov@nvidia.com>
---
include/linux/bitmap.h | 32 +++++++++++++++++
lib/bitmap.c | 46 +++++++++++++++++++------
lib/test_bitmap.c | 78 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 146 insertions(+), 10 deletions(-)
diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h
index 7df1573a409c..d524ef6b0300 100644
--- a/include/linux/bitmap.h
+++ b/include/linux/bitmap.h
@@ -44,6 +44,10 @@ struct device;
* bitmap_fill(dst, nbits) *dst = ~0UL
* bitmap_copy(dst, src, nbits) *dst = *src
* bitmap_and(dst, src1, src2, nbits) *dst = *src1 & *src2
+ * bitmap_and_and(dst, src1, src2, src3, nbits)
+ * *dst = *src1 & *src2 & *src3
+ * bitmap_and_andnot(dst, src1, src2, src3, nbits)
+ * *dst = *src1 & *src2 & ~(*src3)
* bitmap_or(dst, src1, src2, nbits) *dst = *src1 | *src2
* bitmap_weighted_or(dst, src1, src2, nbits) *dst = *src1 | *src2. Returns Hamming Weight of dst
* bitmap_weighted_xor(dst, src1, src2, nbits) *dst = *src1 ^ *src2. Returns Hamming Weight of dst
@@ -166,6 +170,12 @@ void bitmap_cut(unsigned long *dst, const unsigned long *src,
unsigned int first, unsigned int cut, unsigned int nbits);
bool __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
const unsigned long *bitmap2, unsigned int nbits);
+bool __bitmap_and_and(unsigned long *dst, const unsigned long *bitmap1,
+ const unsigned long *bitmap2,
+ const unsigned long *bitmap3, unsigned int nbits);
+bool __bitmap_and_andnot(unsigned long *dst, const unsigned long *bitmap1,
+ const unsigned long *bitmap2,
+ const unsigned long *bitmap3, unsigned int nbits);
void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
const unsigned long *bitmap2, unsigned int nbits);
unsigned int __bitmap_weighted_or(unsigned long *dst, const unsigned long *bitmap1,
@@ -337,6 +347,28 @@ bool bitmap_and(unsigned long *dst, const unsigned long *src1,
return __bitmap_and(dst, src1, src2, nbits);
}
+static __always_inline
+bool bitmap_and_and(unsigned long *dst, const unsigned long *src1,
+ const unsigned long *src2, const unsigned long *src3,
+ unsigned int nbits)
+{
+ if (small_const_nbits(nbits))
+ return (*dst = *src1 & *src2 & *src3 &
+ BITMAP_LAST_WORD_MASK(nbits)) != 0;
+ return __bitmap_and_and(dst, src1, src2, src3, nbits);
+}
+
+static __always_inline
+bool bitmap_and_andnot(unsigned long *dst, const unsigned long *src1,
+ const unsigned long *src2, const unsigned long *src3,
+ unsigned int nbits)
+{
+ if (small_const_nbits(nbits))
+ return (*dst = *src1 & *src2 & ~(*src3) &
+ BITMAP_LAST_WORD_MASK(nbits)) != 0;
+ return __bitmap_and_andnot(dst, src1, src2, src3, nbits);
+}
+
static __always_inline
void bitmap_or(unsigned long *dst, const unsigned long *src1,
const unsigned long *src2, unsigned int nbits)
diff --git a/lib/bitmap.c b/lib/bitmap.c
index ed685127a107..85ce3cbaa9ab 100644
--- a/lib/bitmap.c
+++ b/lib/bitmap.c
@@ -34,6 +34,25 @@
* for the best explanations of this ordering.
*/
+/*
+ * Common helper for bitmap operations.
+ * @FETCH: The expression that fetches and combines each word of the bitmaps
+ * @bits: The bitmap size in bits
+ */
+#define BITMAP_OP(FETCH, bits) \
+({ \
+ unsigned long idx, val, sz = (bits), result = 0; \
+ \
+ for (idx = 0; idx * BITS_PER_LONG < sz; idx++) { \
+ val = (FETCH); \
+ if (sz - idx * BITS_PER_LONG < BITS_PER_LONG) \
+ val &= BITMAP_LAST_WORD_MASK(sz); \
+ result |= (dst[idx] = val); \
+ } \
+ \
+ result != 0; \
+})
+
bool __bitmap_equal(const unsigned long *bitmap1,
const unsigned long *bitmap2, unsigned int bits)
{
@@ -230,19 +249,26 @@ EXPORT_SYMBOL(bitmap_cut);
bool __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
const unsigned long *bitmap2, unsigned int bits)
{
- unsigned int k;
- unsigned int lim = bits/BITS_PER_LONG;
- unsigned long result = 0;
-
- for (k = 0; k < lim; k++)
- result |= (dst[k] = bitmap1[k] & bitmap2[k]);
- if (bits % BITS_PER_LONG)
- result |= (dst[k] = bitmap1[k] & bitmap2[k] &
- BITMAP_LAST_WORD_MASK(bits));
- return result != 0;
+ return BITMAP_OP(bitmap1[idx] & bitmap2[idx], bits);
}
EXPORT_SYMBOL(__bitmap_and);
+bool __bitmap_and_and(unsigned long *dst, const unsigned long *bitmap1,
+ const unsigned long *bitmap2,
+ const unsigned long *bitmap3, unsigned int bits)
+{
+ return BITMAP_OP(bitmap1[idx] & bitmap2[idx] & bitmap3[idx], bits);
+}
+EXPORT_SYMBOL(__bitmap_and_and);
+
+bool __bitmap_and_andnot(unsigned long *dst, const unsigned long *bitmap1,
+ const unsigned long *bitmap2,
+ const unsigned long *bitmap3, unsigned int bits)
+{
+ return BITMAP_OP(bitmap1[idx] & bitmap2[idx] & ~bitmap3[idx], bits);
+}
+EXPORT_SYMBOL(__bitmap_and_andnot);
+
void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
const unsigned long *bitmap2, unsigned int bits)
{
diff --git a/lib/test_bitmap.c b/lib/test_bitmap.c
index 56bd23059b26..fbc46ed960a4 100644
--- a/lib/test_bitmap.c
+++ b/lib/test_bitmap.c
@@ -193,6 +193,81 @@ static void __init test_zero_clear(void)
expect_eq_pbl("", bmap, 1024);
}
+static void __init test_bitmap_and(void)
+{
+ enum { nbits = BITS_PER_LONG + 13 };
+ DECLARE_BITMAP(src1, nbits);
+ DECLARE_BITMAP(src2, nbits);
+ DECLARE_BITMAP(src3, nbits);
+ DECLARE_BITMAP(dst, nbits);
+ DECLARE_BITMAP(expected, nbits);
+ unsigned long small_src1 = ~0UL;
+ unsigned long small_src2 = ~0UL;
+ unsigned long small_src3 = BIT(2);
+ unsigned long small_dst;
+ bool ret;
+
+ ret = bitmap_and_and(&small_dst, &small_src1, &small_src2,
+ &small_src3, 4);
+ expect_eq_ulong(true, ret);
+ expect_eq_ulong(BIT(2), small_dst);
+
+ ret = bitmap_and_andnot(&small_dst, &small_src1, &small_src2,
+ &small_src3, 4);
+ expect_eq_ulong(true, ret);
+ expect_eq_ulong(GENMASK(3, 0) & ~BIT(2), small_dst);
+
+ bitmap_zero(src1, nbits);
+ bitmap_zero(src2, nbits);
+ bitmap_zero(src3, nbits);
+ bitmap_zero(expected, nbits);
+ __set_bit(1, src1);
+ __set_bit(2, src1);
+ __set_bit(BITS_PER_LONG + 1, src1);
+ __set_bit(BITS_PER_LONG + 12, src1);
+ __set_bit(BITS_PER_LONG + 13, src1);
+ __set_bit(1, src2);
+ __set_bit(BITS_PER_LONG + 1, src2);
+ __set_bit(BITS_PER_LONG + 12, src2);
+ __set_bit(BITS_PER_LONG + 13, src2);
+ __set_bit(BITS_PER_LONG + 1, src3);
+ __set_bit(1, expected);
+ __set_bit(BITS_PER_LONG + 1, expected);
+ __set_bit(BITS_PER_LONG + 12, expected);
+
+ ret = bitmap_and(dst, src1, src2, nbits);
+ expect_eq_ulong(true, ret);
+ expect_eq_bitmap(expected, dst, nbits);
+ expect_eq_ulong(BIT(1) | BIT(12), dst[1]);
+
+ bitmap_zero(expected, nbits);
+ __set_bit(BITS_PER_LONG + 1, expected);
+ ret = bitmap_and_and(dst, src1, src2, src3, nbits);
+ expect_eq_ulong(true, ret);
+ expect_eq_bitmap(expected, dst, nbits);
+ expect_eq_ulong(BIT(1), dst[1]);
+
+ bitmap_zero(expected, nbits);
+ __set_bit(1, expected);
+ __set_bit(2, expected);
+ __set_bit(BITS_PER_LONG + 12, expected);
+ ret = bitmap_andnot(dst, src1, src3, nbits);
+ expect_eq_ulong(true, ret);
+ expect_eq_bitmap(expected, dst, nbits);
+ expect_eq_ulong(BIT(12), dst[1]);
+
+ __clear_bit(2, expected);
+ ret = bitmap_and_andnot(src2, src1, src2, src3, nbits);
+ expect_eq_ulong(true, ret);
+ expect_eq_bitmap(expected, src2, nbits);
+ expect_eq_ulong(BIT(12), src2[1]);
+
+ bitmap_fill(src3, nbits);
+ ret = bitmap_and_andnot(src2, src1, src2, src3, nbits);
+ expect_eq_ulong(false, ret);
+ expect_eq_pbl("", src2, nbits);
+}
+
static void __init test_find_nth_bit(void)
{
unsigned long b, bit, cnt = 0;
@@ -1533,6 +1608,8 @@ static void __init test_zero_nbits(void)
bitmap_zero(NULL, 0);
ret = bitmap_and(NULL, NULL, NULL, 0);
+ ret = bitmap_and_and(NULL, NULL, NULL, NULL, 0);
+ ret = bitmap_and_andnot(NULL, NULL, NULL, NULL, 0);
ret = bitmap_empty(NULL, 0);
ret = bitmap_equal(NULL, NULL, 0);
ret = bitmap_full(NULL, 0);
@@ -1566,6 +1643,7 @@ static void __init test_zero_nbits(void)
static void __init selftest(void)
{
test_zero_clear();
+ test_bitmap_and();
test_fill_set();
test_copy();
test_bitmap_region();
--
2.53.0
next prev parent reply other threads:[~2026-09-07 21:54 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-07 21:54 [PATCH 0/9] linkmode: better use bitmap API Yury Norov
2026-09-07 21:54 ` Yury Norov [this message]
2026-09-07 21:54 ` [PATCH 2/9] linkmode: make linkmode_and() return boolean Yury Norov
2026-09-08 13:04 ` Loktionov, Aleksandr
2026-09-07 21:54 ` [PATCH 3/9] net: amd: xgbe: use linkmode_and() return value in xgbe_set_link_ksettings() Yury Norov
2026-09-08 13:04 ` Loktionov, Aleksandr
2026-09-07 21:54 ` [PATCH 4/9] ixgbe: use linkmode_and() return value in ixgbe_get_eee_fw() Yury Norov
2026-09-08 9:09 ` Temerkhanov, Sergey
2026-09-08 13:06 ` Loktionov, Aleksandr
2026-09-07 21:54 ` [PATCH 5/9] net: phy: use linkmode_and() return value in genphy_c45_eee_is_active() Yury Norov
2026-09-08 13:06 ` Loktionov, Aleksandr
2026-09-07 21:54 ` [PATCH 6/9] net: avoid copies before linkmode_and() Yury Norov
2026-09-08 13:07 ` Loktionov, Aleksandr
2026-09-09 11:06 ` Jijie Shao
2026-09-07 21:54 ` [PATCH 7/9] net: phy: use linkmode operation return values in phy_device.c Yury Norov
2026-09-08 13:07 ` Loktionov, Aleksandr
2026-09-08 13:52 ` Andrew Lunn
2026-09-08 15:19 ` Yury Norov
2026-09-09 12:15 ` Andrew Lunn
2026-09-09 8:09 ` Loktionov, Aleksandr
2026-09-07 21:54 ` [PATCH 8/9] r8152: use linkmode_and_and() in EEE checks Yury Norov
2026-09-08 13:12 ` Loktionov, Aleksandr
2026-09-07 21:54 ` [PATCH 9/9] MAINTAINERS: co-maintain linkmode.h under BITMAP Yury Norov
2026-09-08 20:44 ` Jakub Kicinski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260907215439.409858-2-ynorov@nvidia.com \
--to=yury.norov@gmail.com \
--cc=PrashanthKumar.K.R@amd.com \
--cc=Raju.Rangoju@amd.com \
--cc=akpm@linux-foundation.org \
--cc=andrew@lunn.ch \
--cc=anthony.l.nguyen@intel.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=hkallweit1@gmail.com \
--cc=intel-wired-lan@lists.osuosl.org \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=linux@armlinux.org.uk \
--cc=linux@rasmusvillemoes.dk \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=przemyslaw.kitszel@intel.com \
--cc=shaojijie@huawei.com \
--cc=shenjian15@huawei.com \
--cc=ynorov@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.