forked from mirrors/linux
		
	bitmap patches for 6.10
Hi Linus,
 
 Please pull patches for 6.10. This includes:
  - topology_span_sane() optimization from Kyle Meyer;
  - fns() rework from Kuan-Wei Chiu (used in
    cpumask_local_spread() and other places); and
  - headers cleanup from Andy.
 
 This also adds a MAINTAINERS record for bitops API as it's unattended,
 and I'd like to follow it closer.
 
 Thanks,
 Yury
 -----BEGIN PGP SIGNATURE-----
 
 iQGzBAABCgAdFiEEi8GdvG6xMhdgpu/4sUSA/TofvsgFAmZKh/kACgkQsUSA/Tof
 vshtSQv/eT5+KyXg5qCY3fLaIjWYD0uch5jxkdqtib5BncfIrUMsFpZBon+E2x9C
 fWu7K/nfxUjKZF0Sfgl9gVns6K0rC4F24WzHjzWRVVV7+g4idXwMC1kxSX733KQC
 o+D2065Dx9EmhnzypBbmNsGQsQ09WXP1GsJLf8qSGCw0lT1zNtgqsAD5sSogFGGn
 ca9ZsndThuzTst5lXPXipt1W/c26frchh6SgjVTPjzALCDAf5r9Ls5np3AL1AW8X
 yR8cuV9UphT1ysBplzPbBET/Fy/AGbZl1g4u72M6NvGy/nVkQ5Ic4HZj0zIem0Ic
 C60PokY8lg6hQ7tWN8da12/g6WZINgZcfUfuodKiQAzryBGUJlW0aDzDUZPcCqB/
 gmV/Op4RPJeQr9sibQ6nIFx73ydKVQEmZRliahzXR0p33HJCOLTATOeYqLTXQMdi
 ZwhYCqG5fNEUK0VMBy8S4+tEsUAoykU21hFD04b/Ur8A49bxxJ9RDlAUC0IEc1Pj
 fiU0VPFx
 =H6BQ
 -----END PGP SIGNATURE-----
Merge tag 'bitmap-for-6.10v2' of https://github.com/norov/linux
Pull bitmap updates from Yury Norov:
 - topology_span_sane() optimization from Kyle Meyer
 - fns() rework from Kuan-Wei Chiu (used in cpumask_local_spread() and
   other places)
 - headers cleanup from Andy
 - add a MAINTAINERS record for bitops API
* tag 'bitmap-for-6.10v2' of https://github.com/norov/linux:
  usercopy: Don't use "proxy" headers
  bitops: Move aligned_byte_mask() to wordpart.h
  MAINTAINERS: add BITOPS API record
  bitmap: relax find_nth_bit() limitation on return value
  lib: make test_bitops compilable into the kernel image
  bitops: Optimize fns() for improved performance
  lib/test_bitops: Add benchmark test for fns()
  Compiler Attributes: Add __always_used macro
  sched/topology: Optimize topology_span_sane()
  cpumask: Add for_each_cpu_from()
			
			
This commit is contained in:
		
						commit
						4865a27c66
					
				
					 12 changed files with 88 additions and 27 deletions
				
			
		
							
								
								
									
										14
									
								
								MAINTAINERS
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								MAINTAINERS
									
									
									
									
									
								
							|  | @ -3725,6 +3725,20 @@ F:	tools/include/vdso/bits.h | ||||||
| F:	tools/lib/bitmap.c | F:	tools/lib/bitmap.c | ||||||
| F:	tools/lib/find_bit.c | F:	tools/lib/find_bit.c | ||||||
| 
 | 
 | ||||||
|  | BITOPS API | ||||||
|  | M:	Yury Norov <yury.norov@gmail.com> | ||||||
|  | R:	Rasmus Villemoes <linux@rasmusvillemoes.dk> | ||||||
|  | S:	Maintained | ||||||
|  | F:	arch/*/include/asm/bitops.h | ||||||
|  | F:	arch/*/include/asm/bitops_32.h | ||||||
|  | F:	arch/*/include/asm/bitops_64.h | ||||||
|  | F:	arch/*/lib/bitops.c | ||||||
|  | F:	include/asm-generic/bitops | ||||||
|  | F:	include/asm-generic/bitops.h | ||||||
|  | F:	include/linux/bitops.h | ||||||
|  | F:	lib/test_bitops.c | ||||||
|  | F:	tools/*/bitops* | ||||||
|  | 
 | ||||||
| BLINKM RGB LED DRIVER | BLINKM RGB LED DRIVER | ||||||
| M:	Jan-Simon Moeller <jansimon.moeller@gmx.de> | M:	Jan-Simon Moeller <jansimon.moeller@gmx.de> | ||||||
| S:	Maintained | S:	Maintained | ||||||
|  |  | ||||||
|  | @ -8,13 +8,6 @@ | ||||||
| 
 | 
 | ||||||
| #include <uapi/linux/kernel.h> | #include <uapi/linux/kernel.h> | ||||||
| 
 | 
 | ||||||
| /* Set bits in the first 'n' bytes when loaded from memory */ |  | ||||||
| #ifdef __LITTLE_ENDIAN |  | ||||||
| #  define aligned_byte_mask(n) ((1UL << 8*(n))-1) |  | ||||||
| #else |  | ||||||
| #  define aligned_byte_mask(n) (~0xffUL << (BITS_PER_LONG - 8 - 8*(n))) |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #define BITS_PER_TYPE(type)	(sizeof(type) * BITS_PER_BYTE) | #define BITS_PER_TYPE(type)	(sizeof(type) * BITS_PER_BYTE) | ||||||
| #define BITS_TO_LONGS(nr)	__KERNEL_DIV_ROUND_UP(nr, BITS_PER_TYPE(long)) | #define BITS_TO_LONGS(nr)	__KERNEL_DIV_ROUND_UP(nr, BITS_PER_TYPE(long)) | ||||||
| #define BITS_TO_U64(nr)		__KERNEL_DIV_ROUND_UP(nr, BITS_PER_TYPE(u64)) | #define BITS_TO_U64(nr)		__KERNEL_DIV_ROUND_UP(nr, BITS_PER_TYPE(u64)) | ||||||
|  | @ -257,16 +250,10 @@ static inline unsigned int __ffs64(u64 word) | ||||||
|  */ |  */ | ||||||
| static inline unsigned int fns(unsigned long word, unsigned int n) | static inline unsigned int fns(unsigned long word, unsigned int n) | ||||||
| { | { | ||||||
| 	unsigned int bit; | 	while (word && n--) | ||||||
|  | 		word &= word - 1; | ||||||
| 
 | 
 | ||||||
| 	while (word) { | 	return word ? __ffs(word) : BITS_PER_LONG; | ||||||
| 		bit = __ffs(word); |  | ||||||
| 		if (n-- == 0) |  | ||||||
| 			return bit; |  | ||||||
| 		__clear_bit(bit, &word); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return BITS_PER_LONG; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  |  | ||||||
|  | @ -361,6 +361,19 @@ | ||||||
|  */ |  */ | ||||||
| #define __used                          __attribute__((__used__)) | #define __used                          __attribute__((__used__)) | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * The __used attribute guarantees that the attributed variable will be | ||||||
|  |  * always emitted by a compiler. It doesn't prevent the compiler from | ||||||
|  |  * throwing 'unused' warnings when it can't detect how the variable is | ||||||
|  |  * actually used. It's a compiler implementation details either emit | ||||||
|  |  * the warning in that case or not. | ||||||
|  |  * | ||||||
|  |  * The combination of both 'used' and 'unused' attributes ensures that | ||||||
|  |  * the variable would be emitted, and will not trigger 'unused' warnings. | ||||||
|  |  * The attribute is applicable for functions, static and global variables. | ||||||
|  |  */ | ||||||
|  | #define __always_used			__used __maybe_unused | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  *   gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-warn_005funused_005fresult-function-attribute
 |  *   gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-warn_005funused_005fresult-function-attribute
 | ||||||
|  * clang: https://clang.llvm.org/docs/AttributeReference.html#nodiscard-warn-unused-result
 |  * clang: https://clang.llvm.org/docs/AttributeReference.html#nodiscard-warn-unused-result
 | ||||||
|  |  | ||||||
|  | @ -385,6 +385,16 @@ unsigned int __pure cpumask_next_wrap(int n, const struct cpumask *mask, int sta | ||||||
| #define for_each_cpu_or(cpu, mask1, mask2)				\ | #define for_each_cpu_or(cpu, mask1, mask2)				\ | ||||||
| 	for_each_or_bit(cpu, cpumask_bits(mask1), cpumask_bits(mask2), small_cpumask_bits) | 	for_each_or_bit(cpu, cpumask_bits(mask1), cpumask_bits(mask2), small_cpumask_bits) | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * for_each_cpu_from - iterate over CPUs present in @mask, from @cpu to the end of @mask. | ||||||
|  |  * @cpu: the (optionally unsigned) integer iterator | ||||||
|  |  * @mask: the cpumask pointer | ||||||
|  |  * | ||||||
|  |  * After the loop, cpu is >= nr_cpu_ids. | ||||||
|  |  */ | ||||||
|  | #define for_each_cpu_from(cpu, mask)				\ | ||||||
|  | 	for_each_set_bit_from(cpu, cpumask_bits(mask), small_cpumask_bits) | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * cpumask_any_but - return a "random" in a cpumask, but not this one. |  * cpumask_any_but - return a "random" in a cpumask, but not this one. | ||||||
|  * @mask: the cpumask to search |  * @mask: the cpumask to search | ||||||
|  |  | ||||||
|  | @ -222,7 +222,7 @@ unsigned long find_first_bit(const unsigned long *addr, unsigned long size) | ||||||
|  *	 idx = find_first_bit(addr, size); |  *	 idx = find_first_bit(addr, size); | ||||||
|  * |  * | ||||||
|  * Returns the bit number of the N'th set bit. |  * Returns the bit number of the N'th set bit. | ||||||
|  * If no such, returns @size. |  * If no such, returns >= @size. | ||||||
|  */ |  */ | ||||||
| static inline | static inline | ||||||
| unsigned long find_nth_bit(const unsigned long *addr, unsigned long size, unsigned long n) | unsigned long find_nth_bit(const unsigned long *addr, unsigned long size, unsigned long n) | ||||||
|  |  | ||||||
|  | @ -39,4 +39,11 @@ | ||||||
|  */ |  */ | ||||||
| #define REPEAT_BYTE(x)	((~0ul / 0xff) * (x)) | #define REPEAT_BYTE(x)	((~0ul / 0xff) * (x)) | ||||||
| 
 | 
 | ||||||
|  | /* Set bits in the first 'n' bytes when loaded from memory */ | ||||||
|  | #ifdef __LITTLE_ENDIAN | ||||||
|  | #  define aligned_byte_mask(n) ((1UL << 8*(n))-1) | ||||||
|  | #else | ||||||
|  | #  define aligned_byte_mask(n) (~0xffUL << (BITS_PER_LONG - 8 - 8*(n))) | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #endif // _LINUX_WORDPART_H
 | #endif // _LINUX_WORDPART_H
 | ||||||
|  |  | ||||||
|  | @ -2353,7 +2353,7 @@ static struct sched_domain *build_sched_domain(struct sched_domain_topology_leve | ||||||
| static bool topology_span_sane(struct sched_domain_topology_level *tl, | static bool topology_span_sane(struct sched_domain_topology_level *tl, | ||||||
| 			      const struct cpumask *cpu_map, int cpu) | 			      const struct cpumask *cpu_map, int cpu) | ||||||
| { | { | ||||||
| 	int i; | 	int i = cpu + 1; | ||||||
| 
 | 
 | ||||||
| 	/* NUMA levels are allowed to overlap */ | 	/* NUMA levels are allowed to overlap */ | ||||||
| 	if (tl->flags & SDTL_OVERLAP) | 	if (tl->flags & SDTL_OVERLAP) | ||||||
|  | @ -2365,9 +2365,7 @@ static bool topology_span_sane(struct sched_domain_topology_level *tl, | ||||||
| 	 * breaking the sched_group lists - i.e. a later get_group() pass | 	 * breaking the sched_group lists - i.e. a later get_group() pass | ||||||
| 	 * breaks the linking done for an earlier span. | 	 * breaks the linking done for an earlier span. | ||||||
| 	 */ | 	 */ | ||||||
| 	for_each_cpu(i, cpu_map) { | 	for_each_cpu_from(i, cpu_map) { | ||||||
| 		if (i == cpu) |  | ||||||
| 			continue; |  | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * We should 'and' all those masks with 'cpu_map' to exactly | 		 * We should 'and' all those masks with 'cpu_map' to exactly | ||||||
| 		 * match the topology we're about to build, but that can only | 		 * match the topology we're about to build, but that can only | ||||||
|  |  | ||||||
|  | @ -2482,7 +2482,6 @@ config TEST_LKM | ||||||
| 
 | 
 | ||||||
| config TEST_BITOPS | config TEST_BITOPS | ||||||
| 	tristate "Test module for compilation of bitops operations" | 	tristate "Test module for compilation of bitops operations" | ||||||
| 	depends on m |  | ||||||
| 	help | 	help | ||||||
| 	  This builds the "test_bitops" module that is much like the | 	  This builds the "test_bitops" module that is much like the | ||||||
| 	  TEST_LKM module except that it does a basic exercise of the | 	  TEST_LKM module except that it does a basic exercise of the | ||||||
|  |  | ||||||
|  | @ -87,7 +87,7 @@ out:										\ | ||||||
| 	if (sz % BITS_PER_LONG)							\ | 	if (sz % BITS_PER_LONG)							\ | ||||||
| 		tmp = (FETCH) & BITMAP_LAST_WORD_MASK(sz);			\ | 		tmp = (FETCH) & BITMAP_LAST_WORD_MASK(sz);			\ | ||||||
| found:										\ | found:										\ | ||||||
| 	sz = min(idx * BITS_PER_LONG + fns(tmp, nr), sz);			\ | 	sz = idx * BITS_PER_LONG + fns(tmp, nr);				\ | ||||||
| out:										\ | out:										\ | ||||||
| 	sz;									\ | 	sz;									\ | ||||||
| }) | }) | ||||||
|  |  | ||||||
|  | @ -244,7 +244,7 @@ static void __init test_find_nth_bit(void) | ||||||
| 	expect_eq_uint(60,  find_nth_bit(bmap, 64 * 3, 5)); | 	expect_eq_uint(60,  find_nth_bit(bmap, 64 * 3, 5)); | ||||||
| 	expect_eq_uint(80,  find_nth_bit(bmap, 64 * 3, 6)); | 	expect_eq_uint(80,  find_nth_bit(bmap, 64 * 3, 6)); | ||||||
| 	expect_eq_uint(123, find_nth_bit(bmap, 64 * 3, 7)); | 	expect_eq_uint(123, find_nth_bit(bmap, 64 * 3, 7)); | ||||||
| 	expect_eq_uint(64 * 3, find_nth_bit(bmap, 64 * 3, 8)); | 	expect_eq_uint(0,   !!(find_nth_bit(bmap, 64 * 3, 8) < 64 * 3)); | ||||||
| 
 | 
 | ||||||
| 	expect_eq_uint(10,  find_nth_bit(bmap, 64 * 3 - 1, 0)); | 	expect_eq_uint(10,  find_nth_bit(bmap, 64 * 3 - 1, 0)); | ||||||
| 	expect_eq_uint(20,  find_nth_bit(bmap, 64 * 3 - 1, 1)); | 	expect_eq_uint(20,  find_nth_bit(bmap, 64 * 3 - 1, 1)); | ||||||
|  | @ -254,7 +254,7 @@ static void __init test_find_nth_bit(void) | ||||||
| 	expect_eq_uint(60,  find_nth_bit(bmap, 64 * 3 - 1, 5)); | 	expect_eq_uint(60,  find_nth_bit(bmap, 64 * 3 - 1, 5)); | ||||||
| 	expect_eq_uint(80,  find_nth_bit(bmap, 64 * 3 - 1, 6)); | 	expect_eq_uint(80,  find_nth_bit(bmap, 64 * 3 - 1, 6)); | ||||||
| 	expect_eq_uint(123, find_nth_bit(bmap, 64 * 3 - 1, 7)); | 	expect_eq_uint(123, find_nth_bit(bmap, 64 * 3 - 1, 7)); | ||||||
| 	expect_eq_uint(64 * 3 - 1, find_nth_bit(bmap, 64 * 3 - 1, 8)); | 	expect_eq_uint(0,   !!(find_nth_bit(bmap, 64 * 3 - 1, 8) < 64 * 3 - 1)); | ||||||
| 
 | 
 | ||||||
| 	for_each_set_bit(bit, exp1, EXP1_IN_BITS) { | 	for_each_set_bit(bit, exp1, EXP1_IN_BITS) { | ||||||
| 		b = find_nth_bit(exp1, EXP1_IN_BITS, cnt++); | 		b = find_nth_bit(exp1, EXP1_IN_BITS, cnt++); | ||||||
|  |  | ||||||
|  | @ -5,9 +5,11 @@ | ||||||
| 
 | 
 | ||||||
| #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||||||
| 
 | 
 | ||||||
|  | #include <linux/cleanup.h> | ||||||
| #include <linux/init.h> | #include <linux/init.h> | ||||||
| #include <linux/module.h> | #include <linux/module.h> | ||||||
| #include <linux/printk.h> | #include <linux/printk.h> | ||||||
|  | #include <linux/slab.h> | ||||||
| 
 | 
 | ||||||
| /* a tiny module only meant to test
 | /* a tiny module only meant to test
 | ||||||
|  * |  * | ||||||
|  | @ -50,6 +52,30 @@ static unsigned long order_comb_long[][2] = { | ||||||
| }; | }; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | static int __init test_fns(void) | ||||||
|  | { | ||||||
|  | 	static volatile __always_used unsigned long tmp __initdata; | ||||||
|  | 	unsigned long *buf __free(kfree) = NULL; | ||||||
|  | 	unsigned int i, n; | ||||||
|  | 	ktime_t time; | ||||||
|  | 
 | ||||||
|  | 	buf = kmalloc_array(10000, sizeof(unsigned long), GFP_KERNEL); | ||||||
|  | 	if (!buf) | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 
 | ||||||
|  | 	get_random_bytes(buf, 10000 * sizeof(unsigned long)); | ||||||
|  | 	time = ktime_get(); | ||||||
|  | 
 | ||||||
|  | 	for (n = 0; n < BITS_PER_LONG; n++) | ||||||
|  | 		for (i = 0; i < 10000; i++) | ||||||
|  | 			tmp = fns(buf[i], n); | ||||||
|  | 
 | ||||||
|  | 	time = ktime_get() - time; | ||||||
|  | 	pr_err("fns:  %18llu ns\n", time); | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int __init test_bitops_startup(void) | static int __init test_bitops_startup(void) | ||||||
| { | { | ||||||
| 	int i, bit_set; | 	int i, bit_set; | ||||||
|  | @ -94,6 +120,8 @@ static int __init test_bitops_startup(void) | ||||||
| 	if (bit_set != BITOPS_LAST) | 	if (bit_set != BITOPS_LAST) | ||||||
| 		pr_err("ERROR: FOUND SET BIT %d\n", bit_set); | 		pr_err("ERROR: FOUND SET BIT %d\n", bit_set); | ||||||
| 
 | 
 | ||||||
|  | 	test_fns(); | ||||||
|  | 
 | ||||||
| 	pr_info("Completed bitops test\n"); | 	pr_info("Completed bitops test\n"); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -1,9 +1,14 @@ | ||||||
| // SPDX-License-Identifier: GPL-2.0
 | // SPDX-License-Identifier: GPL-2.0
 | ||||||
| #include <linux/bitops.h> | #include <linux/compiler.h> | ||||||
|  | #include <linux/errno.h> | ||||||
|  | #include <linux/export.h> | ||||||
| #include <linux/fault-inject-usercopy.h> | #include <linux/fault-inject-usercopy.h> | ||||||
| #include <linux/instrumented.h> | #include <linux/instrumented.h> | ||||||
| #include <linux/uaccess.h> | #include <linux/kernel.h> | ||||||
| #include <linux/nospec.h> | #include <linux/nospec.h> | ||||||
|  | #include <linux/string.h> | ||||||
|  | #include <linux/uaccess.h> | ||||||
|  | #include <linux/wordpart.h> | ||||||
| 
 | 
 | ||||||
| /* out-of-line parts */ | /* out-of-line parts */ | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Linus Torvalds
						Linus Torvalds