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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox