From 1c88ceb09d5e5506456a625043bc9b35ce86fc41 Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Mon, 14 Sep 2026 16:49:29 -0400 Subject: bitfield: get rid of __MAKE_OP machinery The __MAKE_OP machinery hides the fixed-width bitfield helper definitions from source searches and makes the end result highly obscured and largely uncontrolled. This follows earlier discussions about making these helpers easier to find: [1], [2]. Move the explicit helpers and their shared checks into linux/bitfield-fix-width.h in both the kernel and tools headers, and include it from bitfield.h to preserve existing users. The repeated overflow check is factored into __assert_field(), preserving the original condition and compile-time diagnostics. With GCC 15.2.0 and x86-64 defconfig plus the bitfield KUnit tests, the before/after kernel builds are binary identical. The __MAKE_OP generates the following 40 functions (including the direct ____MAKE_OP(u8,u8,,) invocation): u8_encode_bits() u8_replace_bits() u8p_replace_bits() u8_get_bits() le16_encode_bits() le16_replace_bits() [dead code] le16p_replace_bits() le16_get_bits() be16_encode_bits() be16_replace_bits() [dead code] be16p_replace_bits() [dead code] be16_get_bits() u16_encode_bits() u16_replace_bits() u16p_replace_bits() u16_get_bits() le32_encode_bits() le32_replace_bits() [dead code] le32p_replace_bits() le32_get_bits() be32_encode_bits() be32_replace_bits() [dead code] be32p_replace_bits() be32_get_bits() u32_encode_bits() u32_replace_bits() u32p_replace_bits() u32_get_bits() le64_encode_bits() le64_replace_bits() [dead code] le64p_replace_bits() [dead code] le64_get_bits() be64_encode_bits() be64_replace_bits() [dead code] be64p_replace_bits() [dead code] be64_get_bits() u64_encode_bits() u64_replace_bits() u64p_replace_bits() u64_get_bits() Functions marked with [dead code] have no in-tree callers and are removed by this change. Link: https://lore.kernel.org/all/20250214073402.0129e259@kernel.org/ [1] Link: https://lore.kernel.org/all/aeub59FBHbCy-KKP@yury/ [2] Assisted-by: OpenAI Codex Reviewed-by: Akihiko Odaki Acked-by: Jakub Kicinski Signed-off-by: Yury Norov --- include/linux/bitfield-fix-width.h | 235 +++++++++++++++++++++++++++++++++++++ include/linux/bitfield.h | 49 +------- 2 files changed, 236 insertions(+), 48 deletions(-) create mode 100644 include/linux/bitfield-fix-width.h (limited to 'include') diff --git a/include/linux/bitfield-fix-width.h b/include/linux/bitfield-fix-width.h new file mode 100644 index 000000000000..fba86bb76999 --- /dev/null +++ b/include/linux/bitfield-fix-width.h @@ -0,0 +1,235 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _LINUX_BITFIELD_FIX_WIDTH_H +#define _LINUX_BITFIELD_FIX_WIDTH_H + +#include +#include +#include + +extern void __compiletime_error("value doesn't fit into mask") +__field_overflow(void); + +extern void __compiletime_error("bad bitfield mask") +__bad_mask(void); + +static __always_inline +u64 field_multiplier(u64 field) +{ + if ((field | (field - 1)) & ((field | (field - 1)) + 1)) + __bad_mask(); + return field & -field; +} + +static __always_inline +u64 field_mask(u64 field) +{ + return field / field_multiplier(field); +} + +#define field_max(field) ((typeof(field))field_mask(field)) + +#define __assert_field(v, field) \ + do { \ + if (__builtin_constant_p(v) && \ + ((v) & ~field_mask(field))) \ + __field_overflow(); \ + } while (0) + +static __always_inline __must_check +__u8 u8_encode_bits(u8 v, u8 field) +{ + __assert_field(v, field); + return (v & field_mask(field)) * field_multiplier(field); +} + +static __always_inline __must_check +__u8 u8_replace_bits(__u8 old, u8 val, u8 field) +{ + return (old & ~field) | u8_encode_bits(val, field); +} + +static __always_inline +void u8p_replace_bits(__u8 *p, u8 val, u8 field) +{ + *p = (*p & ~field) | u8_encode_bits(val, field); +} + +static __always_inline __must_check +u8 u8_get_bits(__u8 v, u8 field) +{ + return (v & field) / field_multiplier(field); +} + +static __always_inline __must_check +__le16 le16_encode_bits(u16 v, u16 field) +{ + __assert_field(v, field); + return cpu_to_le16((v & field_mask(field)) * field_multiplier(field)); +} + +static __always_inline +void le16p_replace_bits(__le16 *p, u16 val, u16 field) +{ + *p = (*p & ~cpu_to_le16(field)) | le16_encode_bits(val, field); +} + +static __always_inline __must_check +u16 le16_get_bits(__le16 v, u16 field) +{ + return (le16_to_cpu(v) & field) / field_multiplier(field); +} + +static __always_inline __must_check +__be16 be16_encode_bits(u16 v, u16 field) +{ + __assert_field(v, field); + return cpu_to_be16((v & field_mask(field)) * field_multiplier(field)); +} + +static __always_inline __must_check +u16 be16_get_bits(__be16 v, u16 field) +{ + return (be16_to_cpu(v) & field) / field_multiplier(field); +} + +static __always_inline __must_check +__u16 u16_encode_bits(u16 v, u16 field) +{ + __assert_field(v, field); + return (v & field_mask(field)) * field_multiplier(field); +} + +static __always_inline __must_check +__u16 u16_replace_bits(__u16 old, u16 val, u16 field) +{ + return (old & ~field) | u16_encode_bits(val, field); +} + +static __always_inline +void u16p_replace_bits(__u16 *p, u16 val, u16 field) +{ + *p = (*p & ~field) | u16_encode_bits(val, field); +} + +static __always_inline __must_check +u16 u16_get_bits(__u16 v, u16 field) +{ + return (v & field) / field_multiplier(field); +} + +static __always_inline __must_check +__le32 le32_encode_bits(u32 v, u32 field) +{ + __assert_field(v, field); + return cpu_to_le32((v & field_mask(field)) * field_multiplier(field)); +} + +static __always_inline +void le32p_replace_bits(__le32 *p, u32 val, u32 field) +{ + *p = (*p & ~cpu_to_le32(field)) | le32_encode_bits(val, field); +} + +static __always_inline __must_check +u32 le32_get_bits(__le32 v, u32 field) +{ + return (le32_to_cpu(v) & field) / field_multiplier(field); +} + +static __always_inline __must_check +__be32 be32_encode_bits(u32 v, u32 field) +{ + __assert_field(v, field); + return cpu_to_be32((v & field_mask(field)) * field_multiplier(field)); +} + +static __always_inline +void be32p_replace_bits(__be32 *p, u32 val, u32 field) +{ + *p = (*p & ~cpu_to_be32(field)) | be32_encode_bits(val, field); +} + +static __always_inline __must_check +u32 be32_get_bits(__be32 v, u32 field) +{ + return (be32_to_cpu(v) & field) / field_multiplier(field); +} + +static __always_inline __must_check +__u32 u32_encode_bits(u32 v, u32 field) +{ + __assert_field(v, field); + return (v & field_mask(field)) * field_multiplier(field); +} + +static __always_inline __must_check +__u32 u32_replace_bits(__u32 old, u32 val, u32 field) +{ + return (old & ~field) | u32_encode_bits(val, field); +} + +static __always_inline +void u32p_replace_bits(__u32 *p, u32 val, u32 field) +{ + *p = (*p & ~field) | u32_encode_bits(val, field); +} + +static __always_inline __must_check +u32 u32_get_bits(__u32 v, u32 field) +{ + return (v & field) / field_multiplier(field); +} + +static __always_inline __must_check +__le64 le64_encode_bits(u64 v, u64 field) +{ + __assert_field(v, field); + return cpu_to_le64((v & field_mask(field)) * field_multiplier(field)); +} + +static __always_inline __must_check +u64 le64_get_bits(__le64 v, u64 field) +{ + return (le64_to_cpu(v) & field) / field_multiplier(field); +} + +static __always_inline __must_check +__be64 be64_encode_bits(u64 v, u64 field) +{ + __assert_field(v, field); + return cpu_to_be64((v & field_mask(field)) * field_multiplier(field)); +} + +static __always_inline __must_check +u64 be64_get_bits(__be64 v, u64 field) +{ + return (be64_to_cpu(v) & field) / field_multiplier(field); +} + +static __always_inline __must_check +__u64 u64_encode_bits(u64 v, u64 field) +{ + __assert_field(v, field); + return (v & field_mask(field)) * field_multiplier(field); +} + +static __always_inline __must_check +__u64 u64_replace_bits(__u64 old, u64 val, u64 field) +{ + return (old & ~field) | u64_encode_bits(val, field); +} + +static __always_inline +void u64p_replace_bits(__u64 *p, u64 val, u64 field) +{ + *p = (*p & ~field) | u64_encode_bits(val, field); +} + +static __always_inline __must_check +u64 u64_get_bits(__u64 v, u64 field) +{ + return (v & field) / field_multiplier(field); +} + +#endif /* _LINUX_BITFIELD_FIX_WIDTH_H */ diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h index 14f86e455a67..e3f7315c1d53 100644 --- a/include/linux/bitfield.h +++ b/include/linux/bitfield.h @@ -10,7 +10,7 @@ #include #include #include -#include +#include /* * Bitfield access macros @@ -211,53 +211,6 @@ *(_reg_p) |= (((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask)); \ }) -extern void __compiletime_error("value doesn't fit into mask") -__field_overflow(void); -extern void __compiletime_error("bad bitfield mask") -__bad_mask(void); -static __always_inline u64 field_multiplier(u64 field) -{ - if ((field | (field - 1)) & ((field | (field - 1)) + 1)) - __bad_mask(); - return field & -field; -} -static __always_inline u64 field_mask(u64 field) -{ - return field / field_multiplier(field); -} -#define field_max(field) ((typeof(field))field_mask(field)) -#define ____MAKE_OP(type,base,to,from) \ -static __always_inline __##type __must_check type##_encode_bits(base v, base field) \ -{ \ - if (__builtin_constant_p(v) && (v & ~field_mask(field))) \ - __field_overflow(); \ - return to((v & field_mask(field)) * field_multiplier(field)); \ -} \ -static __always_inline __##type __must_check type##_replace_bits(__##type old, \ - base val, base field) \ -{ \ - return (old & ~to(field)) | type##_encode_bits(val, field); \ -} \ -static __always_inline void type##p_replace_bits(__##type *p, \ - base val, base field) \ -{ \ - *p = (*p & ~to(field)) | type##_encode_bits(val, field); \ -} \ -static __always_inline base __must_check type##_get_bits(__##type v, base field) \ -{ \ - return (from(v) & field)/field_multiplier(field); \ -} -#define __MAKE_OP(size) \ - ____MAKE_OP(le##size,u##size,cpu_to_le##size,le##size##_to_cpu) \ - ____MAKE_OP(be##size,u##size,cpu_to_be##size,be##size##_to_cpu) \ - ____MAKE_OP(u##size,u##size,,) -____MAKE_OP(u8,u8,,) -__MAKE_OP(16) -__MAKE_OP(32) -__MAKE_OP(64) -#undef __MAKE_OP -#undef ____MAKE_OP - #define __field_prep(mask, val) \ ({ \ auto __mask = (mask); \ -- cgit v1.2.3 From d267d2f41222912a5f40dc064df64cee57c8bade Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 23 Sep 2026 23:09:53 +0100 Subject: bitfield: Restore be16_replace_bits() Commit 1c88ceb09d5e5 ("bitfield: get rid of __MAKE_OP machinery") removed a bunch of unused bitfield operations including be16_replace_bits() but commit 508bdb4938928 ("iio: adc: Add AD7768 and AD7768-4 core support") introduces a new user. Restore the function so the build still works once both branches are merged. Signed-off-by: Mark Brown Signed-off-by: Yury Norov --- include/linux/bitfield-fix-width.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'include') diff --git a/include/linux/bitfield-fix-width.h b/include/linux/bitfield-fix-width.h index fba86bb76999..f73b8cd65601 100644 --- a/include/linux/bitfield-fix-width.h +++ b/include/linux/bitfield-fix-width.h @@ -93,6 +93,12 @@ u16 be16_get_bits(__be16 v, u16 field) return (be16_to_cpu(v) & field) / field_multiplier(field); } +static __always_inline __must_check +__be16 be16_replace_bits(__be16 old, u16 val, u16 field) +{ + return (old & ~cpu_to_be16(field)) | be16_encode_bits(val, field); +} + static __always_inline __must_check __u16 u16_encode_bits(u16 v, u16 field) { -- cgit v1.2.3