From 6b5a4b68736798df1031404a2fad06d031253ef7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 26 Feb 2026 12:16:44 +0100 Subject: [PATCH 01/24] bitmap: Add test for out-of-boundary modifications for scatter & gather Make sure that bitmap_scatter() and bitmap_gather() do not modify the bits outside of the given nbits span. Signed-off-by: Andy Shevchenko Signed-off-by: Yury Norov --- lib/test_bitmap.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/test_bitmap.c b/lib/test_bitmap.c index c83829ef557f..2952a6147e81 100644 --- a/lib/test_bitmap.c +++ b/lib/test_bitmap.c @@ -354,18 +354,22 @@ static void __init test_replace(void) static const unsigned long sg_mask[] __initconst = { BITMAP_FROM_U64(0x000000000000035aULL), + BITMAP_FROM_U64(0x0000000000000000ULL), }; static const unsigned long sg_src[] __initconst = { BITMAP_FROM_U64(0x0000000000000667ULL), + BITMAP_FROM_U64(0x0000000000000000ULL), }; static const unsigned long sg_gather_exp[] __initconst = { BITMAP_FROM_U64(0x0000000000000029ULL), + BITMAP_FROM_U64(0x0000000000000000ULL), }; static const unsigned long sg_scatter_exp[] __initconst = { BITMAP_FROM_U64(0x000000000000021aULL), + BITMAP_FROM_U64(0x0000000000000000ULL), }; static void __init test_bitmap_sg(void) @@ -379,18 +383,18 @@ static void __init test_bitmap_sg(void) /* Simple gather call */ bitmap_zero(bmap_gather, 100); bitmap_gather(bmap_gather, sg_src, sg_mask, nbits); - expect_eq_bitmap(sg_gather_exp, bmap_gather, nbits); + expect_eq_bitmap(sg_gather_exp, bmap_gather, 100); /* Simple scatter call */ bitmap_zero(bmap_scatter, 100); bitmap_scatter(bmap_scatter, sg_src, sg_mask, nbits); - expect_eq_bitmap(sg_scatter_exp, bmap_scatter, nbits); + expect_eq_bitmap(sg_scatter_exp, bmap_scatter, 100); /* Scatter/gather relationship */ bitmap_zero(bmap_tmp, 100); bitmap_gather(bmap_tmp, bmap_scatter, sg_mask, nbits); bitmap_scatter(bmap_res, bmap_tmp, sg_mask, nbits); - expect_eq_bitmap(bmap_scatter, bmap_res, nbits); + expect_eq_bitmap(bmap_scatter, bmap_res, 100); } #define PARSE_TIME 0x1 From d1a43793c484e4f1e896dd2fee52b034f8c4f965 Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Thu, 19 Feb 2026 13:13:57 -0500 Subject: [PATCH 02/24] bitmap: switch test to scnprintf("%*pbl") scnprintf("%*pbl") is more verbose than bitmap_print_to_pagebuf(). Switch the test to using it. This also improves the test output because bitmap_print_to_pagebuf() adds \n at the end of the printed bitmap, which breaks the test format. Signed-off-by: Yury Norov --- lib/test_bitmap.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/test_bitmap.c b/lib/test_bitmap.c index 2952a6147e81..8d07b5411897 100644 --- a/lib/test_bitmap.c +++ b/lib/test_bitmap.c @@ -548,22 +548,22 @@ static void __init test_bitmap_printlist(void) goto out; time = ktime_get(); - ret = bitmap_print_to_pagebuf(true, buf, bmap, PAGE_SIZE * 8); + ret = scnprintf(buf, PAGE_SIZE, "%*pbl", (int)PAGE_SIZE * 8, bmap); time = ktime_get() - time; - if (ret != slen + 1) { - pr_err("bitmap_print_to_pagebuf: result is %d, expected %d\n", ret, slen); + if (ret != slen) { + pr_err("bitmap_printlist: result is %d, expected %d\n", ret, slen); failed_tests++; goto out; } if (strncmp(buf, expected, slen)) { - pr_err("bitmap_print_to_pagebuf: result is %s, expected %s\n", buf, expected); + pr_err("bitmap_printlist: result is %s, expected %s\n", buf, expected); failed_tests++; goto out; } - pr_info("bitmap_print_to_pagebuf: input is '%s', Time: %llu\n", buf, time); + pr_info("bitmap_printlist: input is '%s', Time: %llu\n", buf, time); out: kfree(buf); kfree(bmap); From e63375d39a2e90edc25e96560f14d28193347b04 Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Thu, 19 Feb 2026 13:13:58 -0500 Subject: [PATCH 03/24] bitmap: align test_bitmap output Different subtests print output in slightly different formats. Unify the format for better visual representation. The test output before: [ 0.553474] test_bitmap: parselist: 14: input is '0-2047:128/256' OK, Time: 202 [ 0.555121] test_bitmap: bitmap_print_to_pagebuf: input is '0-32767 [ 0.555121] ', Time: 1278 [ 0.578392] test_bitmap: Time spent in test_bitmap_read_perf: 427864 [ 0.580137] test_bitmap: Time spent in test_bitmap_write_perf: 793554 [ 0.581957] test_bitmap: all 390447 tests passed And after: [ 0.314982] test_bitmap: parselist('0-2047:128/256'): 135 [ 0.315517] test_bitmap: scnprintf("%*pbl", '0-32767'): 342 [ 0.330045] test_bitmap: test_bitmap_read_perf: 252294 [ 0.331132] test_bitmap: test_bitmap_write_perf: 539001 [ 0.332163] test_bitmap: all 390447 tests passed Signed-off-by: Yury Norov --- lib/test_bitmap.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/test_bitmap.c b/lib/test_bitmap.c index 8d07b5411897..1c352c1edfa5 100644 --- a/lib/test_bitmap.c +++ b/lib/test_bitmap.c @@ -524,8 +524,7 @@ static void __init test_bitmap_parselist(void) } if (ptest.flags & PARSE_TIME) - pr_info("parselist: %d: input is '%s' OK, Time: %llu\n", - i, ptest.in, time); + pr_info("parselist('%s'):\t%llu\n", ptest.in, time); #undef ptest } @@ -552,18 +551,18 @@ static void __init test_bitmap_printlist(void) time = ktime_get() - time; if (ret != slen) { - pr_err("bitmap_printlist: result is %d, expected %d\n", ret, slen); + pr_err("scnprintf(\"%%*pbl\"): result is %d, expected %d\n", ret, slen); failed_tests++; goto out; } if (strncmp(buf, expected, slen)) { - pr_err("bitmap_printlist: result is %s, expected %s\n", buf, expected); + pr_err("scnprintf(\"%%*pbl\"): result is %s, expected %s\n", buf, expected); failed_tests++; goto out; } - pr_info("bitmap_printlist: input is '%s', Time: %llu\n", buf, time); + pr_info("scnprintf(\"%%*pbl\", '%s'):\t%llu\n", buf, time); out: kfree(buf); kfree(bmap); @@ -1399,7 +1398,7 @@ static void __init test_bitmap_read_perf(void) } } time = ktime_get() - time; - pr_info("Time spent in %s:\t%llu\n", __func__, time); + pr_info("%s:\t\t%llu\n", __func__, time); } static void __init test_bitmap_write_perf(void) @@ -1421,7 +1420,7 @@ static void __init test_bitmap_write_perf(void) } } time = ktime_get() - time; - pr_info("Time spent in %s:\t%llu\n", __func__, time); + pr_info("%s:\t\t%llu\n", __func__, time); } #undef TEST_BIT_LEN From a676643709115816d3ce7e50aa5b5a4af1ee6c45 Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Wed, 25 Feb 2026 18:58:32 -0500 Subject: [PATCH 04/24] bitmap: drop __find_nth_andnot_bit() Remove find_nth_andnot_bit() leftovers. CC: Rasmus Villemoes CC: Andrew Morton CC: Shaopeng Tan Fixes: b0c85e99458a ("cpumask: Remove unnecessary cpumask_nth_andnot()") Signed-off-by: Yury Norov --- include/linux/find.h | 2 -- lib/find_bit.c | 7 ------- 2 files changed, 9 deletions(-) diff --git a/include/linux/find.h b/include/linux/find.h index 9d720ad92bc1..6c2be8ca615d 100644 --- a/include/linux/find.h +++ b/include/linux/find.h @@ -22,8 +22,6 @@ extern unsigned long _find_first_bit(const unsigned long *addr, unsigned long si unsigned long __find_nth_bit(const unsigned long *addr, unsigned long size, unsigned long n); unsigned long __find_nth_and_bit(const unsigned long *addr1, const unsigned long *addr2, unsigned long size, unsigned long n); -unsigned long __find_nth_andnot_bit(const unsigned long *addr1, const unsigned long *addr2, - unsigned long size, unsigned long n); unsigned long __find_nth_and_andnot_bit(const unsigned long *addr1, const unsigned long *addr2, const unsigned long *addr3, unsigned long size, unsigned long n); diff --git a/lib/find_bit.c b/lib/find_bit.c index 5a0066c26d9a..5ac52dfce730 100644 --- a/lib/find_bit.c +++ b/lib/find_bit.c @@ -172,13 +172,6 @@ unsigned long __find_nth_and_bit(const unsigned long *addr1, const unsigned long } EXPORT_SYMBOL(__find_nth_and_bit); -unsigned long __find_nth_andnot_bit(const unsigned long *addr1, const unsigned long *addr2, - unsigned long size, unsigned long n) -{ - return FIND_NTH_BIT(addr1[idx] & ~addr2[idx], size, n); -} -EXPORT_SYMBOL(__find_nth_andnot_bit); - unsigned long __find_nth_and_andnot_bit(const unsigned long *addr1, const unsigned long *addr2, const unsigned long *addr3, From 6c88ba561cfc2c5f35067519f46310059a9dc39a Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Wed, 11 Mar 2026 00:21:26 +0900 Subject: [PATCH 05/24] lib/find_bit_benchmark: avoid clearing randomly filled bitmap in test_find_first_bit() test_find_first_bit() searches for a set bit from the beginning of the test bitmap and clears it repeatedly, eventually clearing the entire bitmap. After test_find_first_bit() is executed, test_find_first_and_bit() and test_find_next_and_bit() are executed without randomly reinitializing the cleared bitmap. In the first phase (testing find_bit() with a random-filled bitmap), test_find_first_bit() only operates on 1/10 of the entire size of the testing bitmap, so this isn't a big problem. However, in the second phase (testing find_bit() with a sparse bitmap), test_find_first_bit() clears the entire test bitmap, so the subsequent test_find_first_and_bit() and test_find_next_and_bit() will not find any set bits. This is probably not the intended benchmark. To fix this issue, test_find_first_bit() operates on a duplicated bitmap and does not clear the original test bitmap. The same is already done in test_find_first_and_bit(). While we're at it, add const qualifiers to the bitmap pointer arguments in the test functions. Signed-off-by: Akinobu Mita Cc: Rasmus Villemoes Signed-off-by: Yury Norov --- lib/find_bit_benchmark.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/find_bit_benchmark.c b/lib/find_bit_benchmark.c index 402e160e7186..00d9dc61cd46 100644 --- a/lib/find_bit_benchmark.c +++ b/lib/find_bit_benchmark.c @@ -30,18 +30,20 @@ static DECLARE_BITMAP(bitmap, BITMAP_LEN) __initdata; static DECLARE_BITMAP(bitmap2, BITMAP_LEN) __initdata; /* - * This is Schlemiel the Painter's algorithm. It should be called after - * all other tests for the same bitmap because it sets all bits of bitmap to 1. + * This is Schlemiel the Painter's algorithm. */ -static int __init test_find_first_bit(void *bitmap, unsigned long len) +static int __init test_find_first_bit(const void *bitmap, unsigned long len) { + static DECLARE_BITMAP(cp, BITMAP_LEN) __initdata; unsigned long i, cnt; ktime_t time; + bitmap_copy(cp, bitmap, BITMAP_LEN); + time = ktime_get(); for (cnt = i = 0; i < len; cnt++) { - i = find_first_bit(bitmap, len); - __clear_bit(i, bitmap); + i = find_first_bit(cp, len); + __clear_bit(i, cp); } time = ktime_get() - time; pr_err("find_first_bit: %18llu ns, %6ld iterations\n", time, cnt); @@ -49,7 +51,8 @@ static int __init test_find_first_bit(void *bitmap, unsigned long len) return 0; } -static int __init test_find_first_and_bit(void *bitmap, const void *bitmap2, unsigned long len) +static int __init test_find_first_and_bit(const void *bitmap, const void *bitmap2, + unsigned long len) { static DECLARE_BITMAP(cp, BITMAP_LEN) __initdata; unsigned long i, cnt; From bf31ddc14f8c6bcd4987c31fe2bc9e93e433b41a Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Mon, 22 Dec 2025 14:11:37 -0500 Subject: [PATCH 06/24] bitmap: add bitmap_weight_from() The function calculates a Hamming weight of a bitmap starting from an arbitrary bit. Signed-off-by: Yury Norov --- include/linux/bitmap.h | 33 +++++++++++++++++++++++++++++++++ lib/test_bitmap.c | 26 ++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h index b0395e4ccf90..9c0d1de44350 100644 --- a/include/linux/bitmap.h +++ b/include/linux/bitmap.h @@ -57,6 +57,7 @@ struct device; * bitmap_weight(src, nbits) Hamming Weight: number set bits * bitmap_weight_and(src1, src2, nbits) Hamming Weight of and'ed bitmap * bitmap_weight_andnot(src1, src2, nbits) Hamming Weight of andnot'ed bitmap + * bitmap_weight_from(src, start, end) Hamming Weight starting from @start * bitmap_set(dst, pos, nbits) Set specified bit area * bitmap_clear(dst, pos, nbits) Clear specified bit area * bitmap_find_next_zero_area(buf, len, pos, n, mask) Find bit free area @@ -479,6 +480,38 @@ unsigned long bitmap_weight_andnot(const unsigned long *src1, return __bitmap_weight_andnot(src1, src2, nbits); } +/** + * bitmap_weight_from - Hamming weight for a memory region + * @bitmap: The base address + * @start: The bitnumber to starts weighting + * @end: the bitmap size in bits + * + * Returns the number of set bits in the region. If @start >= @end, + * return >= end. + */ +static __always_inline +unsigned long bitmap_weight_from(const unsigned long *bitmap, + unsigned int start, unsigned int end) +{ + unsigned long w; + + if (unlikely(start >= end)) + return end; + + if (small_const_nbits(end)) + return hweight_long(*bitmap & GENMASK(end - 1, start)); + + bitmap += start / BITS_PER_LONG; + /* Opencode round_down() to not include math.h */ + end -= start & ~(BITS_PER_LONG - 1); + start %= BITS_PER_LONG; + w = bitmap_weight(bitmap, end); + if (start) + w -= hweight_long(*bitmap & BITMAP_LAST_WORD_MASK(start)); + + return w; +} + static __always_inline void bitmap_set(unsigned long *map, unsigned int start, unsigned int nbits) { diff --git a/lib/test_bitmap.c b/lib/test_bitmap.c index 1c352c1edfa5..cd4cb36e42a5 100644 --- a/lib/test_bitmap.c +++ b/lib/test_bitmap.c @@ -854,6 +854,31 @@ static void __init test_for_each_set_bit_from(void) } } +static void __init test_bitmap_weight(void) +{ + unsigned int bit, w1, w2, w; + DECLARE_BITMAP(b, 30); + + bitmap_parselist("all:1/2", b, 30); + + /* Test inline implementation */ + w = bitmap_weight(b, 30); + w1 = bitmap_weight(b, 15); + w2 = bitmap_weight_from(b, 15, 30); + + expect_eq_uint(15, w); + expect_eq_uint(8, w1); + expect_eq_uint(7, w2); + + /* Test outline implementation */ + w = bitmap_weight(exp1, EXP1_IN_BITS); + for (bit = 0; bit < EXP1_IN_BITS; bit++) { + w1 = bitmap_weight(exp1, bit); + w2 = bitmap_weight_from(exp1, bit, EXP1_IN_BITS); + expect_eq_uint(w1 + w2, w); + } +} + static void __init test_for_each_clear_bit(void) { DECLARE_BITMAP(orig, 500); @@ -1444,6 +1469,7 @@ static void __init selftest(void) test_bitmap_const_eval(); test_bitmap_read_write(); test_bitmap_read_perf(); + test_bitmap_weight(); test_bitmap_write_perf(); test_find_nth_bit(); From c6a98dff41bfb4ccc2c7f4ed596bcbf6994d5d1a Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Mon, 22 Dec 2025 14:11:38 -0500 Subject: [PATCH 07/24] x86/topology: use bitmap_weight_from() Switch topo_unit_count() to use bitmap_weight_from(). Signed-off-by: Yury Norov --- arch/x86/kernel/cpu/topology.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/arch/x86/kernel/cpu/topology.c b/arch/x86/kernel/cpu/topology.c index eafcb1fc185a..4913b64ec592 100644 --- a/arch/x86/kernel/cpu/topology.c +++ b/arch/x86/kernel/cpu/topology.c @@ -204,15 +204,11 @@ fwbug: static unsigned int topo_unit_count(u32 lvlid, enum x86_topology_domains at_level, unsigned long *map) { - unsigned int id, end, cnt = 0; + unsigned int end; /* Calculate the exclusive end */ end = lvlid + (1U << x86_topo_system.dom_shifts[at_level]); - - /* Unfortunately there is no bitmap_weight_range() */ - for (id = find_next_bit(map, end, lvlid); id < end; id = find_next_bit(map, end, ++id)) - cnt++; - return cnt; + return bitmap_weight_from(map, lvlid, end); } static __init void topo_register_apic(u32 apic_id, u32 acpi_id, bool present) From 18c48899653fa7a04120537c228031b5c7e4e9d6 Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Tue, 10 Mar 2026 16:53:02 -0400 Subject: [PATCH 08/24] lib: crypto: fix comments for count_leading_zeros() count_leading_zeros() is based on fls(), which is defined for x == 0, contrary to __ffs() family. The comment in crypto/mpi erroneously states that the function may return undef in such case. Fix the comment together with the outdated function signature, and now that COUNT_LEADING_ZEROS_0 is not referenced in the codebase, get rid of it too. Reviewed-by: Andy Shevchenko Acked-by: Eric Biggers Signed-off-by: Yury Norov --- include/linux/count_zeros.h | 4 +--- lib/crypto/mpi/longlong.h | 8 ++++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/include/linux/count_zeros.h b/include/linux/count_zeros.h index 5b8ff5ac660d..4e5680327ece 100644 --- a/include/linux/count_zeros.h +++ b/include/linux/count_zeros.h @@ -18,7 +18,7 @@ * * If the MSB of @x is set, the result is 0. * If only the LSB of @x is set, then the result is BITS_PER_LONG-1. - * If @x is 0 then the result is COUNT_LEADING_ZEROS_0. + * If @x is 0 then the result is BITS_PER_LONG. */ static inline int count_leading_zeros(unsigned long x) { @@ -28,8 +28,6 @@ static inline int count_leading_zeros(unsigned long x) return BITS_PER_LONG - fls64(x); } -#define COUNT_LEADING_ZEROS_0 BITS_PER_LONG - /** * count_trailing_zeros - Count the number of zeros from the LSB forwards * @x: The value diff --git a/lib/crypto/mpi/longlong.h b/lib/crypto/mpi/longlong.h index b6fa1d08fb55..6d31c3a729f1 100644 --- a/lib/crypto/mpi/longlong.h +++ b/lib/crypto/mpi/longlong.h @@ -66,12 +66,12 @@ * denominator). Like udiv_qrnnd but the numbers are signed. The quotient * is rounded towards 0. * - * 5) count_leading_zeros(count, x) counts the number of zero-bits from the + * 5) count_leading_zeros(x) counts the number of zero-bits from the * msb to the first non-zero bit in the UWtype X. This is the number of - * steps X needs to be shifted left to set the msb. Undefined for X == 0, - * unless the symbol COUNT_LEADING_ZEROS_0 is defined to some value. + * steps X needs to be shifted left to set the msb. + * count_leading_zeros(0) == BITS_PER_LONG * - * 6) count_trailing_zeros(count, x) like count_leading_zeros, but counts + * 6) count_trailing_zeros() like count_leading_zeros(), but counts * from the least significant end. * * 7) add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1, From 4e64c91b813f666dffc3962a815a8a50b7d6f468 Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Thu, 12 Mar 2026 19:08:16 -0400 Subject: [PATCH 09/24] lib: count_zeros: fix 32/64-bit inconsistency in count_trailing_zeros() Based on 'sizeof(x) == 4' condition, in 32-bit case the function is wired to ffs(), while in 64-bit case to __ffs(). The difference is substantial: ffs(x) == __ffs(x) + 1. Also, ffs(0) == 0, while __ffs(0) is undefined. The 32-bit behaviour is inconsistent with the function description, so it needs to get fixed. There are 9 individual users for the function in 6 different subsystems. Some arches and drivers are 64-bit only: - arch/loongarch/kvm/intc/eiointc.c; - drivers/hv/mshv_vtl_main.c; - kernel/liveupdate/kexec_handover.c; The others are: - ib_umem_find_best_pgsz(): as per comment, __ffs() should be correct; - rzv2m_csi_reg_write_bit(): ARCH_RENESAS only, unclear; - lz77_match_len(): CIFS_COMPRESSION only, unclear, experimental; IB and CIFS are explicitly OK with the change. The attached patch gets rid of 32-bit explicit support, so that both 32- and 64-bit versions rely on __ffs(). CC: K. Y. Srinivasan CC: Haiyang Zhang CC: Mark Brown CC: Steve French CC: Alexander Graf CC: Mike Rapoport CC: Pasha Tatashin Acked-by: Leon Romanovsky Signed-off-by: Yury Norov --- include/linux/count_zeros.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/include/linux/count_zeros.h b/include/linux/count_zeros.h index 4e5680327ece..5034a30b5c7c 100644 --- a/include/linux/count_zeros.h +++ b/include/linux/count_zeros.h @@ -10,6 +10,8 @@ #include +#define COUNT_TRAILING_ZEROS_0 (-1) + /** * count_leading_zeros - Count the number of zeros from the MSB back * @x: The value @@ -40,12 +42,7 @@ static inline int count_leading_zeros(unsigned long x) */ static inline int count_trailing_zeros(unsigned long x) { -#define COUNT_TRAILING_ZEROS_0 (-1) - - if (sizeof(x) == 4) - return ffs(x); - else - return (x != 0) ? __ffs(x) : COUNT_TRAILING_ZEROS_0; + return (x != 0) ? __ffs(x) : COUNT_TRAILING_ZEROS_0; } #endif /* _LINUX_BITOPS_COUNT_ZEROS_H_ */ From be56db15fcce8bb8bd85f236382276d52ce73d08 Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Mon, 23 Mar 2026 12:17:12 -0400 Subject: [PATCH 10/24] lib: count_zeros: unify count_{leading,trailing}_zeros() The 'leading' helper returns BITS_PER_LONG if x == 0, while 'trailing' one returns COUNT_TRAILING_ZEROS_0, which turns to be -1. None of the current users explicitly check the returned value for COUNT_TRAILING_ZEROS_0, except the loongarch, which tests implicitly for the '>= 0'. So, align count_trailing_zeros() with the count_leading_zeros(), and simplify the loongarch handling. Reviewed-by: Andy Shevchenko Signed-off-by: Yury Norov --- arch/loongarch/kvm/intc/eiointc.c | 4 ++-- include/linux/count_zeros.h | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/arch/loongarch/kvm/intc/eiointc.c b/arch/loongarch/kvm/intc/eiointc.c index d2acb4d09e73..3b5268116727 100644 --- a/arch/loongarch/kvm/intc/eiointc.c +++ b/arch/loongarch/kvm/intc/eiointc.c @@ -16,7 +16,7 @@ static void eiointc_set_sw_coreisr(struct loongarch_eiointc *s) ipnum = (s->ipmap >> (irq / 32 * 8)) & 0xff; if (!(s->status & BIT(EIOINTC_ENABLE_INT_ENCODE))) { ipnum = count_trailing_zeros(ipnum); - ipnum = (ipnum >= 0 && ipnum < 4) ? ipnum : 0; + ipnum = ipnum < 4 ? ipnum : 0; } cpuid = ((u8 *)s->coremap)[irq]; @@ -41,7 +41,7 @@ static void eiointc_update_irq(struct loongarch_eiointc *s, int irq, int level) ipnum = (s->ipmap >> (irq / 32 * 8)) & 0xff; if (!(s->status & BIT(EIOINTC_ENABLE_INT_ENCODE))) { ipnum = count_trailing_zeros(ipnum); - ipnum = (ipnum >= 0 && ipnum < 4) ? ipnum : 0; + ipnum = ipnum < 4 ? ipnum : 0; } cpu = s->sw_coremap[irq]; diff --git a/include/linux/count_zeros.h b/include/linux/count_zeros.h index 5034a30b5c7c..b72ba3faa036 100644 --- a/include/linux/count_zeros.h +++ b/include/linux/count_zeros.h @@ -10,8 +10,6 @@ #include -#define COUNT_TRAILING_ZEROS_0 (-1) - /** * count_leading_zeros - Count the number of zeros from the MSB back * @x: The value @@ -38,11 +36,11 @@ static inline int count_leading_zeros(unsigned long x) * * If the LSB of @x is set, the result is 0. * If only the MSB of @x is set, then the result is BITS_PER_LONG-1. - * If @x is 0 then the result is COUNT_TRAILING_ZEROS_0. + * If @x is 0 then the result is BITS_PER_LONG. */ static inline int count_trailing_zeros(unsigned long x) { - return (x != 0) ? __ffs(x) : COUNT_TRAILING_ZEROS_0; + return x ? __ffs(x) : BITS_PER_LONG; } #endif /* _LINUX_BITOPS_COUNT_ZEROS_H_ */ From 7b52b262f8a8cd96dac33721389a884420c18365 Mon Sep 17 00:00:00 2001 From: Kit Dallege Date: Sun, 15 Mar 2026 16:34:14 +0100 Subject: [PATCH 11/24] bitops: fix kernel-doc parameter name for parity8() The kernel-doc comment for parity8() documents the parameter as @value but the actual parameter name is @val. Fix the mismatch. Assisted-by: Claude Signed-off-by: Kit Dallege Signed-off-by: Yury Norov --- include/linux/bitops.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/bitops.h b/include/linux/bitops.h index ea7898cc5903..1fe46703792f 100644 --- a/include/linux/bitops.h +++ b/include/linux/bitops.h @@ -230,7 +230,7 @@ static inline int get_count_order_long(unsigned long l) /** * parity8 - get the parity of an u8 value - * @value: the value to be examined + * @val: the value to be examined * * Determine the parity of the u8 argument. * From f3e9c1138e9d20677ed085107cd2872d5218e3b1 Mon Sep 17 00:00:00 2001 From: Kai Huang Date: Fri, 20 Mar 2026 20:59:38 +1300 Subject: [PATCH 12/24] asm-generic/bitops: Fix a comment typo in instrumented-atomic.h The comment after the '#endif' at the end of the instrumented-atomic.h is a typo. The "NON_ATOMIC" part should be "ATOMIC". Fix it. Signed-off-by: Kai Huang Signed-off-by: Yury Norov --- include/asm-generic/bitops/instrumented-atomic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-generic/bitops/instrumented-atomic.h b/include/asm-generic/bitops/instrumented-atomic.h index 4225a8ca9c1a..c010d54275e4 100644 --- a/include/asm-generic/bitops/instrumented-atomic.h +++ b/include/asm-generic/bitops/instrumented-atomic.h @@ -100,4 +100,4 @@ static __always_inline bool test_and_change_bit(long nr, volatile unsigned long return arch_test_and_change_bit(nr, addr); } -#endif /* _ASM_GENERIC_BITOPS_INSTRUMENTED_NON_ATOMIC_H */ +#endif /* _ASM_GENERIC_BITOPS_INSTRUMENTED_ATOMIC_H */ From e9cf8f83c9857a32494002c72b5f6e36ff4dfcd5 Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Wed, 18 Mar 2026 20:43:46 -0400 Subject: [PATCH 13/24] bitmap: test bitmap_weight() for more Test the function for correctness when some bits are set in the last word of bitmap beyond nbits. This is motivated by commit a9dadc1c512807f9 ("powerpc/xive: Fix the size of the cpumask used in xive_find_target_in_mask()"). Signed-off-by: Yury Norov --- lib/test_bitmap.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lib/test_bitmap.c b/lib/test_bitmap.c index cd4cb36e42a5..eeb497016ed3 100644 --- a/lib/test_bitmap.c +++ b/lib/test_bitmap.c @@ -858,6 +858,7 @@ static void __init test_bitmap_weight(void) { unsigned int bit, w1, w2, w; DECLARE_BITMAP(b, 30); + DECLARE_BITMAP(b1, 128); bitmap_parselist("all:1/2", b, 30); @@ -877,6 +878,24 @@ static void __init test_bitmap_weight(void) w2 = bitmap_weight_from(exp1, bit, EXP1_IN_BITS); expect_eq_uint(w1 + w2, w); } + + /* Test out-of-range */ + w = bitmap_weight_from(b, 31, 30); + expect_eq_uint(0, !!(w < 30)); + + /* + * Test bitmap_weight() for correctness in case of some bits set between + * nbits and end of the last word. + */ + bitmap_fill(b1, 128); + + /* Inline */ + expect_eq_uint(30, bitmap_weight(b1, 30)); + expect_eq_uint(100, bitmap_weight(b1, 100)); + + /* Outline */ + for (int i = 1; i < 128; i++) + expect_eq_uint(i, bitmap_weight(b1, i)); } static void __init test_for_each_clear_bit(void) From 2a4d3706d864d19ba8772b7a5e74328ac5c1007d Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Wed, 18 Mar 2026 20:43:47 -0400 Subject: [PATCH 14/24] bitmap: exclude nbits == 0 cases from bitmap test Bitmap API handles nbits == 0 in most cases correctly, i.e. it doesn't dereferene underlying bitmap and returns a sane value where convenient, or implementation defined, or undef. Implicitly testing nbits == 0 case, however, may make an impression that this is a regular case. This is wrong. In most cases nbits == 0 is a sign of an error on a client side. The tests should not make such an implression. This patch reworks the existing tests to not test nbits == 0. The following patch adds an explicit test for it with an appropriate precaution. Signed-off-by: Yury Norov --- lib/test_bitmap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/test_bitmap.c b/lib/test_bitmap.c index eeb497016ed3..b6f27c632c75 100644 --- a/lib/test_bitmap.c +++ b/lib/test_bitmap.c @@ -653,7 +653,7 @@ static void __init test_bitmap_arr32(void) memset(arr, 0xa5, sizeof(arr)); - for (nbits = 0; nbits < EXP1_IN_BITS; ++nbits) { + for (nbits = 1; nbits < EXP1_IN_BITS; ++nbits) { bitmap_to_arr32(arr, exp1, nbits); bitmap_from_arr32(bmap2, arr, nbits); expect_eq_bitmap(bmap2, exp1, nbits); @@ -681,7 +681,7 @@ static void __init test_bitmap_arr64(void) memset(arr, 0xa5, sizeof(arr)); - for (nbits = 0; nbits < EXP1_IN_BITS; ++nbits) { + for (nbits = 1; nbits < EXP1_IN_BITS; ++nbits) { memset(bmap2, 0xff, sizeof(arr)); bitmap_to_arr64(arr, exp1, nbits); bitmap_from_arr64(bmap2, arr, nbits); @@ -714,7 +714,7 @@ static void noinline __init test_mem_optimisations(void) unsigned int start, nbits; for (start = 0; start < 1024; start += 8) { - for (nbits = 0; nbits < 1024 - start; nbits += 8) { + for (nbits = 1; nbits < 1024 - start; nbits += 8) { memset(bmap1, 0x5a, sizeof(bmap1)); memset(bmap2, 0x5a, sizeof(bmap2)); @@ -873,7 +873,7 @@ static void __init test_bitmap_weight(void) /* Test outline implementation */ w = bitmap_weight(exp1, EXP1_IN_BITS); - for (bit = 0; bit < EXP1_IN_BITS; bit++) { + for (bit = 1; bit < EXP1_IN_BITS; bit++) { w1 = bitmap_weight(exp1, bit); w2 = bitmap_weight_from(exp1, bit, EXP1_IN_BITS); expect_eq_uint(w1 + w2, w); From 95d324fb1b48434f4c659e4c245c3bdeecdff22c Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Wed, 18 Mar 2026 20:43:48 -0400 Subject: [PATCH 15/24] bitmap: add test_zero_nbits() In most real-life cases, 0-length bitmap provided by user is a sign of an error. The API doesn't provide any guarantees on returned value, and the bitmap pointers are not dereferenced. Signed-off-by: Yury Norov --- lib/bitmap.c | 2 ++ lib/test_bitmap.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/lib/bitmap.c b/lib/bitmap.c index 9dc526507875..1b897f94e0ff 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c @@ -69,6 +69,7 @@ bool __bitmap_or_equal(const unsigned long *bitmap1, tmp = (bitmap1[k] | bitmap2[k]) ^ bitmap3[k]; return (tmp & BITMAP_LAST_WORD_MASK(bits)) == 0; } +EXPORT_SYMBOL(__bitmap_or_equal); void __bitmap_complement(unsigned long *dst, const unsigned long *src, unsigned int bits) { @@ -360,6 +361,7 @@ unsigned int __bitmap_weighted_or(unsigned long *dst, const unsigned long *bitma { return BITMAP_WEIGHT(({dst[idx] = bitmap1[idx] | bitmap2[idx]; dst[idx]; }), bits); } +EXPORT_SYMBOL(__bitmap_weighted_or); void __bitmap_set(unsigned long *map, unsigned int start, int len) { diff --git a/lib/test_bitmap.c b/lib/test_bitmap.c index b6f27c632c75..69813c10e6c0 100644 --- a/lib/test_bitmap.c +++ b/lib/test_bitmap.c @@ -1467,6 +1467,62 @@ static void __init test_bitmap_write_perf(void) pr_info("%s:\t\t%llu\n", __func__, time); } +/* + * nbits == 0 is most commonly not a valid case. Bitmap users should revisit + * the caller logic. Bitmap API doesn't provide any guarantees on returned + * value. The pointers are not dereferenced. The return value is intentionally + * ignored. + */ +static void __init test_zero_nbits(void) +{ + static volatile __always_used unsigned long ret __initdata; + + bitmap_clear(NULL, 0, 0); + bitmap_complement(NULL, NULL, 0); + bitmap_copy(NULL, NULL, 0); + bitmap_copy_clear_tail(NULL, NULL, 0); + bitmap_fill(NULL, 0); + bitmap_from_arr32(NULL, NULL, 0); + bitmap_from_arr64(NULL, NULL, 0); + bitmap_or(NULL, NULL, NULL, 0); + bitmap_set(NULL, 0, 0); + bitmap_shift_left(NULL, NULL, 0, 0); + bitmap_shift_right(NULL, NULL, 0, 0); + bitmap_to_arr32(NULL, NULL, 0); + bitmap_to_arr64(NULL, NULL, 0); + bitmap_write(NULL, 0, 0, 0); + bitmap_xor(NULL, NULL, NULL, 0); + bitmap_zero(NULL, 0); + + ret = bitmap_and(NULL, NULL, NULL, 0); + ret = bitmap_empty(NULL, 0); + ret = bitmap_equal(NULL, NULL, 0); + ret = bitmap_full(NULL, 0); + ret = bitmap_or_equal(NULL, NULL, NULL, 0); + ret = bitmap_read(NULL, 0, 0); + ret = bitmap_subset(NULL, NULL, 0); + ret = bitmap_weight(NULL, 0); + ret = bitmap_weight_and(NULL, NULL, 0); + ret = bitmap_weight_andnot(NULL, NULL, 0); + ret = bitmap_weight_from(NULL, 0, 0); + ret = bitmap_weighted_or(NULL, NULL, NULL, 0); + + ret = find_first_and_and_bit(NULL, NULL, NULL, 0); + ret = find_first_and_bit(NULL, NULL, 0); + ret = find_first_andnot_bit(NULL, NULL, 0); + ret = find_first_bit(NULL, 0); + ret = find_first_zero_bit(NULL, 0); + ret = find_last_bit(NULL, 0); + ret = find_next_and_bit(NULL, NULL, 0, 0); + ret = find_next_andnot_bit(NULL, NULL, 0, 0); + ret = find_next_bit(NULL, 0, 0); + ret = find_next_clump8(NULL, NULL, 0, 0); + ret = find_next_zero_bit(NULL, 0, 0); + ret = find_nth_and_bit(NULL, NULL, 0, 0); + ret = find_nth_bit(NULL, 0, 0); + ret = find_random_bit(NULL, 0); +} + #undef TEST_BIT_LEN static void __init selftest(void) @@ -1490,6 +1546,7 @@ static void __init selftest(void) test_bitmap_read_perf(); test_bitmap_weight(); test_bitmap_write_perf(); + test_zero_nbits(); test_find_nth_bit(); test_for_each_set_bit(); From d57e74f10461b80c77d1678f646720f616fb8553 Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Sun, 1 Mar 2026 20:11:55 -0500 Subject: [PATCH 16/24] bitmap: introduce bitmap_weighted_xor() The function helps to XOR bitmaps and calculate Hamming weight of the result in one pass. Reviewed-by: Aleksandr Loktionov Reviewed-by: Jacob Keller Signed-off-by: Yury Norov --- include/linux/bitmap.h | 15 +++++++++++++++ lib/bitmap.c | 7 +++++++ 2 files changed, 22 insertions(+) diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h index 9c0d1de44350..b007d54a9036 100644 --- a/include/linux/bitmap.h +++ b/include/linux/bitmap.h @@ -46,6 +46,7 @@ struct device; * bitmap_and(dst, src1, src2, nbits) *dst = *src1 & *src2 * 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 * bitmap_xor(dst, src1, src2, nbits) *dst = *src1 ^ *src2 * bitmap_andnot(dst, src1, src2, nbits) *dst = *src1 & ~(*src2) * bitmap_complement(dst, src, nbits) *dst = ~(*src) @@ -169,6 +170,8 @@ 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, const unsigned long *bitmap2, unsigned int nbits); +unsigned int __bitmap_weighted_xor(unsigned long *dst, const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int nbits); void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1, const unsigned long *bitmap2, unsigned int nbits); bool __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1, @@ -353,6 +356,18 @@ unsigned int bitmap_weighted_or(unsigned long *dst, const unsigned long *src1, } } +static __always_inline +unsigned int bitmap_weighted_xor(unsigned long *dst, const unsigned long *src1, + const unsigned long *src2, unsigned int nbits) +{ + if (small_const_nbits(nbits)) { + *dst = *src1 ^ *src2; + return hweight_long(*dst & BITMAP_LAST_WORD_MASK(nbits)); + } else { + return __bitmap_weighted_xor(dst, src1, src2, nbits); + } +} + static __always_inline void bitmap_xor(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 1b897f94e0ff..b9bfa157e095 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c @@ -363,6 +363,13 @@ unsigned int __bitmap_weighted_or(unsigned long *dst, const unsigned long *bitma } EXPORT_SYMBOL(__bitmap_weighted_or); +unsigned int __bitmap_weighted_xor(unsigned long *dst, const unsigned long *bitmap1, + const unsigned long *bitmap2, unsigned int bits) +{ + return BITMAP_WEIGHT(({dst[idx] = bitmap1[idx] ^ bitmap2[idx]; dst[idx]; }), bits); +} +EXPORT_SYMBOL(__bitmap_weighted_xor); + void __bitmap_set(unsigned long *map, unsigned int start, int len) { unsigned long *p = map + BIT_WORD(start); From bdeaa653aeff7316581c51507937f4f925d68cbc Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Sun, 1 Mar 2026 20:11:56 -0500 Subject: [PATCH 17/24] ice: use bitmap_weighted_xor() in ice_find_free_recp_res_idx() Use the right helper and save one bitmaps traverse. Reviewed-by: Aleksandr Loktionov Reviewed-by: Jacob Keller Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Yury Norov --- drivers/net/ethernet/intel/ice/ice_switch.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index bb0f990fa2c6..6a5875bd9c6b 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -4984,10 +4984,8 @@ ice_find_free_recp_res_idx(struct ice_hw *hw, const unsigned long *profiles, hw->switch_info->recp_list[bit].res_idxs, ICE_MAX_FV_WORDS); - bitmap_xor(free_idx, used_idx, possible_idx, ICE_MAX_FV_WORDS); - /* return number of free indexes */ - return (u16)bitmap_weight(free_idx, ICE_MAX_FV_WORDS); + return (u16)bitmap_weighted_xor(free_idx, used_idx, possible_idx, ICE_MAX_FV_WORDS); } /** From 82e68aa4a6b16aa060d5044116dac957631cf6f0 Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Sun, 1 Mar 2026 20:11:57 -0500 Subject: [PATCH 18/24] ice: use bitmap_empty() in ice_vf_has_no_qs_ena bitmap_empty() is more verbose and efficient, as it stops traversing {r,t}xq_ena as soon as the 1st set bit found. Tested-by: Rafal Romanowski Reviewed-by: Aleksandr Loktionov Reviewed-by: Jacob Keller Signed-off-by: Yury Norov --- drivers/net/ethernet/intel/ice/ice_vf_lib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c index c8bc952f05cd..772f6b07340d 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c @@ -1210,8 +1210,8 @@ bool ice_is_vf_trusted(struct ice_vf *vf) */ bool ice_vf_has_no_qs_ena(struct ice_vf *vf) { - return (!bitmap_weight(vf->rxq_ena, ICE_MAX_RSS_QS_PER_VF) && - !bitmap_weight(vf->txq_ena, ICE_MAX_RSS_QS_PER_VF)); + return bitmap_empty(vf->rxq_ena, ICE_MAX_RSS_QS_PER_VF) && + bitmap_empty(vf->txq_ena, ICE_MAX_RSS_QS_PER_VF); } /** From ac679a6e0fccab0e30ea04c97a3a0713b8b722ae Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Sun, 1 Mar 2026 20:11:58 -0500 Subject: [PATCH 19/24] drm/xe: switch xe_pagefault_queue_init() to using bitmap_weighted_or() The function calls bitmap_or() immediately followed by bitmap_weight(). Switch to using the dedicated bitmap_weighted_or() and save one bitmap traverse. Reviewed-by: Matthew Brost Reviewed-by: Aleksandr Loktionov Reviewed-by: Jacob Keller Signed-off-by: Yury Norov --- drivers/gpu/drm/xe/xe_pagefault.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_pagefault.c b/drivers/gpu/drm/xe/xe_pagefault.c index 6bee53d6ffc3..c4ce3cfe2164 100644 --- a/drivers/gpu/drm/xe/xe_pagefault.c +++ b/drivers/gpu/drm/xe/xe_pagefault.c @@ -285,10 +285,9 @@ static int xe_pagefault_queue_init(struct xe_device *xe, xe_dss_mask_t all_dss; int num_dss, num_eus; - bitmap_or(all_dss, gt->fuse_topo.g_dss_mask, + num_dss = bitmap_weighted_or(all_dss, gt->fuse_topo.g_dss_mask, gt->fuse_topo.c_dss_mask, XE_MAX_DSS_FUSE_BITS); - num_dss = bitmap_weight(all_dss, XE_MAX_DSS_FUSE_BITS); num_eus = bitmap_weight(gt->fuse_topo.eu_mask_per_dss, XE_MAX_EU_FUSE_BITS) * num_dss; From 7ca1d7f939964e31fe8ecbca70d96423d511fb93 Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Tue, 3 Mar 2026 15:08:40 -0500 Subject: [PATCH 20/24] lib/prime_numbers: drop temporary buffer in dump_primes() The function uses temporary buffer to convert primes bitmap into human readable format. Switch to using kunit_info("%*pbl")", and drop the buffer. Signed-off-by: Yury Norov --- lib/math/tests/prime_numbers_kunit.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/math/tests/prime_numbers_kunit.c b/lib/math/tests/prime_numbers_kunit.c index 2f1643208c66..55ac160c6dfa 100644 --- a/lib/math/tests/prime_numbers_kunit.c +++ b/lib/math/tests/prime_numbers_kunit.c @@ -8,12 +8,10 @@ static void dump_primes(void *ctx, const struct primes *p) { - static char buf[PAGE_SIZE]; struct kunit_suite *suite = ctx; - bitmap_print_to_pagebuf(true, buf, p->primes, p->sz); - kunit_info(suite, "primes.{last=%lu, .sz=%lu, .primes[]=...x%lx} = %s", - p->last, p->sz, p->primes[BITS_TO_LONGS(p->sz) - 1], buf); + kunit_info(suite, "primes.{last=%lu, .sz=%lu, .primes[]=...x%lx} = %*pbl", + p->last, p->sz, p->primes[BITS_TO_LONGS(p->sz) - 1], (int)p->sz, p->primes); } static void prime_numbers_test(struct kunit *test) From 6f3aa76b3db44f93013702348c31d479931e681d Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Tue, 3 Mar 2026 15:08:39 -0500 Subject: [PATCH 21/24] coresight: don't use bitmap_print_to_pagebuf() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch the driver to using the proper sysfs_emit("%*pbl") where appropriate. Suggested-by: Thomas Weißschuh Signed-off-by: Yury Norov --- .../hwtracing/coresight/coresight-cti-sysfs.c | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-cti-sysfs.c b/drivers/hwtracing/coresight/coresight-cti-sysfs.c index 572b80ee96fb..26ec0d8ed181 100644 --- a/drivers/hwtracing/coresight/coresight-cti-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-cti-sysfs.c @@ -606,14 +606,11 @@ static ssize_t chan_gate_enable_show(struct device *dev, struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); struct cti_config *cfg = &drvdata->config; unsigned long ctigate_bitmask = cfg->ctigate; - int size = 0; if (cfg->ctigate == 0) - size = sprintf(buf, "\n"); - else - size = bitmap_print_to_pagebuf(true, buf, &ctigate_bitmask, - cfg->nr_ctm_channels); - return size; + return sprintf(buf, "\n"); + + return sysfs_emit(buf, "%*pbl\n", cfg->nr_ctm_channels, &ctigate_bitmask); } static DEVICE_ATTR_RW(chan_gate_enable); @@ -710,12 +707,13 @@ static ssize_t trigout_filtered_show(struct device *dev, { struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); struct cti_config *cfg = &drvdata->config; - int size = 0, nr_trig_max = cfg->nr_trig_max; + int nr_trig_max = cfg->nr_trig_max; unsigned long mask = cfg->trig_out_filter; - if (mask) - size = bitmap_print_to_pagebuf(true, buf, &mask, nr_trig_max); - return size; + if (mask == 0) + return 0; + + return sysfs_emit(buf, "%*pbl\n", nr_trig_max, &mask); } static DEVICE_ATTR_RO(trigout_filtered); @@ -834,7 +832,7 @@ static ssize_t print_chan_list(struct device *dev, { struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); struct cti_config *config = &drvdata->config; - int size, i; + int i; unsigned long inuse_bits = 0, chan_mask; /* scan regs to get bitmap of channels in use. */ @@ -852,11 +850,9 @@ static ssize_t print_chan_list(struct device *dev, /* list of channels, or 'none' */ chan_mask = GENMASK(config->nr_ctm_channels - 1, 0); if (inuse_bits & chan_mask) - size = bitmap_print_to_pagebuf(true, buf, &inuse_bits, - config->nr_ctm_channels); - else - size = sprintf(buf, "\n"); - return size; + return sysfs_emit(buf, "%*pbl\n", config->nr_ctm_channels, &inuse_bits); + + return sprintf(buf, "\n"); } static ssize_t chan_inuse_show(struct device *dev, @@ -928,7 +924,7 @@ static ssize_t trigin_sig_show(struct device *dev, struct cti_config *cfg = &drvdata->config; unsigned long mask = con->con_in->used_mask; - return bitmap_print_to_pagebuf(true, buf, &mask, cfg->nr_trig_max); + return sysfs_emit(buf, "%*pbl\n", cfg->nr_trig_max, &mask); } static ssize_t trigout_sig_show(struct device *dev, @@ -942,7 +938,7 @@ static ssize_t trigout_sig_show(struct device *dev, struct cti_config *cfg = &drvdata->config; unsigned long mask = con->con_out->used_mask; - return bitmap_print_to_pagebuf(true, buf, &mask, cfg->nr_trig_max); + return sysfs_emit(buf, "%*pbl\n", cfg->nr_trig_max, &mask); } /* convert a sig type id to a name */ From f3d8bb94255117aa7b405c949277c874c1c496f0 Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Tue, 3 Mar 2026 15:08:38 -0500 Subject: [PATCH 22/24] thermal: intel: switch cpumask_get() to using cpumask_print_to_pagebuf() The function opencodes cpumask_print_to_pagebuf() with more generic bitmap_print_to_pagebuf(). Switch to using the proper API. Signed-off-by: Yury Norov --- drivers/thermal/intel/intel_powerclamp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/thermal/intel/intel_powerclamp.c b/drivers/thermal/intel/intel_powerclamp.c index 9a4cec000910..ccf380da12f2 100644 --- a/drivers/thermal/intel/intel_powerclamp.c +++ b/drivers/thermal/intel/intel_powerclamp.c @@ -200,8 +200,7 @@ static int cpumask_get(char *buf, const struct kernel_param *kp) if (!cpumask_available(idle_injection_cpu_mask)) return -ENODEV; - return bitmap_print_to_pagebuf(false, buf, cpumask_bits(idle_injection_cpu_mask), - nr_cpumask_bits); + return cpumap_print_to_pagebuf(false, buf, idle_injection_cpu_mask); } static const struct kernel_param_ops cpumask_ops = { From 4ff568ce3ca66573e8b97b0caaa12b971dd38ae3 Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Tue, 3 Mar 2026 15:08:37 -0500 Subject: [PATCH 23/24] powerpc/xive: simplify xive_spapr_debug_show() The function creates temporary buffer to convert xibm->bitmap to a human-readable list before passing it to seq_printf. Drop it and print the list by seq_printf() directly with the "%*pbl" specifier. Reviewed-by: Shrikanth Hegde Acked-by: Madhavan Srinivasan for powerpc patch Signed-off-by: Yury Norov --- arch/powerpc/sysdev/xive/spapr.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/sysdev/xive/spapr.c b/arch/powerpc/sysdev/xive/spapr.c index 61f8a8acf81f..fdf52c78ac02 100644 --- a/arch/powerpc/sysdev/xive/spapr.c +++ b/arch/powerpc/sysdev/xive/spapr.c @@ -667,17 +667,9 @@ static void xive_spapr_sync_source(u32 hw_irq) static int xive_spapr_debug_show(struct seq_file *m, void *private) { struct xive_irq_bitmap *xibm; - char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - list_for_each_entry(xibm, &xive_irq_bitmaps, list) { - memset(buf, 0, PAGE_SIZE); - bitmap_print_to_pagebuf(true, buf, xibm->bitmap, xibm->count); - seq_printf(m, "bitmap #%d: %s", xibm->count, buf); - } - kfree(buf); + list_for_each_entry(xibm, &xive_irq_bitmaps, list) + seq_printf(m, "bitmap #%d: %*pbl\n", xibm->count, xibm->count, xibm->bitmap); return 0; } From 592a22338e5acfcd10983699cae8ea02ecd42935 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 7 Apr 2026 17:14:31 +0200 Subject: [PATCH 24/24] bitops: Update kernel-doc for sign_extendXX() The sign_extendXX() lack of Return section and have other style issues. Address that by updating kernel-doc accordingly. Signed-off-by: Andy Shevchenko Signed-off-by: Yury Norov --- include/linux/bitops.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/include/linux/bitops.h b/include/linux/bitops.h index 1fe46703792f..657eab2725ce 100644 --- a/include/linux/bitops.h +++ b/include/linux/bitops.h @@ -179,9 +179,11 @@ static inline __u8 ror8(__u8 word, unsigned int shift) /** * sign_extend32 - sign extend a 32-bit value using specified bit as sign-bit * @value: value to sign extend - * @index: 0 based bit index (0<=index<32) to sign bit + * @index: 0 based bit index (0 <= index < 32) to sign bit * * This is safe to use for 16- and 8-bit types as well. + * + * Return: 32-bit sign extended value */ static __always_inline __s32 sign_extend32(__u32 value, int index) { @@ -192,7 +194,11 @@ static __always_inline __s32 sign_extend32(__u32 value, int index) /** * sign_extend64 - sign extend a 64-bit value using specified bit as sign-bit * @value: value to sign extend - * @index: 0 based bit index (0<=index<64) to sign bit + * @index: 0 based bit index (0 <= index < 64) to sign bit + * + * This is safe to use for 32-, 16- and 8-bit types as well. + * + * Return: 64-bit sign extended value */ static __always_inline __s64 sign_extend64(__u64 value, int index) {