* [PATCH 0/9] bitfield: tidy up bitfield.h
@ 2025-12-08 22:42 david.laight.linux
2025-12-08 22:42 ` [PATCH 1/9] nfp: Call FIELD_PREP() in NFP_ETH_SET_BIT_CONFIG() wrapper david.laight.linux
` (9 more replies)
0 siblings, 10 replies; 23+ messages in thread
From: david.laight.linux @ 2025-12-08 22:42 UTC (permalink / raw)
To: Yury Norov, Rasmus Villemoes, linux-kernel, linux-usb,
Geert Uytterhoeven
Cc: David Laight, Alexandre Belloni, Jonathan Cameron, Crt Mori,
Richard Genoud, Andy Shevchenko, Luo Jie, Peter Zijlstra,
Jakub Kicinski, netdev, David S . Miller, Simon Horman,
Mika Westerberg, Andreas Noever, Yehezkel Bernat
From: David Laight <david.laight.linux@gmail.com>
I noticed some very long (18KB) error messages from the compiler.
Turned out they were errors on lines that passed GENMASK() to FIELD_PREP().
Since most of the #defines are already statement functions the values
can be copied to locals so the actual parameters only get expanded once.
The 'bloat' is reduced further by using a simple test to ensure 'reg'
is large enough, slightly simplifying the test for constant 'val' and
only checking 'reg' and 'val' when the parameters are present.
The first two patches are slightly problematic.
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c manages to use
a #define that should be an internal to bitfield.h, the changed file
is actually more similar to the previous version.
drivers/thunderbolt/tb.h passes a bifield to FIELD_GET(), these can't
be used with sizeof or __auto_type. The usual solution is to add zero,
but that can't be done in FIELD_GET() because it doesn't want the value
promoted to 'int' (no idea how _Generic() treated it.)
The fix is just to add zero at the call site.
(The bitfield seems to be in a structure rad from hardware - no idea
how that works on BE (or any LE that uses an unusual order for bitfields.)
Both changes may need to to through the same tree as the header file changes.
The changes are based on 'next' and contain the addition of field_prep()
and field_get() for non-constant values.
I also know it is the merge window.
I expect to be generating a v2 in the new year (someone always has a comment).
David Laight (9):
nfp: Call FIELD_PREP() in NFP_ETH_SET_BIT_CONFIG() wrapper
thunderblot: Don't pass a bitfield to FIELD_GET
bitmap: Use FIELD_PREP() in expansion of FIELD_PREP_WM16()
bitfield: Copy #define parameters to locals
bitfield: FIELD_MODIFY: Only do a single read/write on the target
bitfield: Update sanity checks
bitfield: Reduce indentation
bitfield: Add comment block for the host/fixed endian functions
bitfield: Update comments for le/be functions
.../netronome/nfp/nfpcore/nfp_nsp_eth.c | 16 +-
drivers/thunderbolt/tb.h | 2 +-
include/linux/bitfield.h | 278 ++++++++++--------
include/linux/hw_bitfield.h | 17 +-
4 files changed, 166 insertions(+), 147 deletions(-)
--
2.39.5
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 1/9] nfp: Call FIELD_PREP() in NFP_ETH_SET_BIT_CONFIG() wrapper
2025-12-08 22:42 [PATCH 0/9] bitfield: tidy up bitfield.h david.laight.linux
@ 2025-12-08 22:42 ` david.laight.linux
2025-12-08 22:42 ` [PATCH 2/9] thunderblot: Don't pass a bitfield to FIELD_GET david.laight.linux
` (8 subsequent siblings)
9 siblings, 0 replies; 23+ messages in thread
From: david.laight.linux @ 2025-12-08 22:42 UTC (permalink / raw)
To: Yury Norov, Rasmus Villemoes, linux-kernel, linux-usb,
Geert Uytterhoeven
Cc: David Laight
From: David Laight <david.laight.linux@gmail.com>
Rather than use a define that should be internal to the implementation
of FIELD_PREP(), pass the shifted 'val' to nfp_eth_set_bit_config()
and change the test for 'value unchanged' to match.
This is a simpler change than the one used to avoid calling both
FIELD_GET() and FIELD_PREP() with non-constant mask values.
Signed-off-by: David Laight <david.laight.linux@gmail.com>
---
.../ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c | 16 ++++++----------
1 file changed, 6 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c
index 5cfddc9a5d87..4a71ff47fbef 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c
@@ -509,8 +509,7 @@ int nfp_eth_set_configured(struct nfp_cpp *cpp, unsigned int idx, bool configed)
static int
nfp_eth_set_bit_config(struct nfp_nsp *nsp, unsigned int raw_idx,
- const u64 mask, const unsigned int shift,
- u64 val, const u64 ctrl_bit)
+ const u64 mask, u64 shifted_val, const u64 ctrl_bit)
{
union eth_table_entry *entries = nfp_nsp_config_entries(nsp);
unsigned int idx = nfp_nsp_config_idx(nsp);
@@ -527,11 +526,11 @@ nfp_eth_set_bit_config(struct nfp_nsp *nsp, unsigned int raw_idx,
/* Check if we are already in requested state */
reg = le64_to_cpu(entries[idx].raw[raw_idx]);
- if (val == (reg & mask) >> shift)
+ if (shifted_val == (reg & mask))
return 0;
reg &= ~mask;
- reg |= (val << shift) & mask;
+ reg |= shifted_val;
entries[idx].raw[raw_idx] = cpu_to_le64(reg);
entries[idx].control |= cpu_to_le64(ctrl_bit);
@@ -571,12 +570,9 @@ int nfp_eth_set_idmode(struct nfp_cpp *cpp, unsigned int idx, bool state)
return nfp_eth_config_commit_end(nsp);
}
-#define NFP_ETH_SET_BIT_CONFIG(nsp, raw_idx, mask, val, ctrl_bit) \
- ({ \
- __BF_FIELD_CHECK(mask, 0ULL, val, "NFP_ETH_SET_BIT_CONFIG: "); \
- nfp_eth_set_bit_config(nsp, raw_idx, mask, __bf_shf(mask), \
- val, ctrl_bit); \
- })
+#define NFP_ETH_SET_BIT_CONFIG(nsp, raw_idx, mask, val, ctrl_bit) \
+ nfp_eth_set_bit_config(nsp, raw_idx, mask, FIELD_PREP(mask, val), \
+ ctrl_bit)
/**
* __nfp_eth_set_aneg() - set PHY autonegotiation control bit
--
2.39.5
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 2/9] thunderblot: Don't pass a bitfield to FIELD_GET
2025-12-08 22:42 [PATCH 0/9] bitfield: tidy up bitfield.h david.laight.linux
2025-12-08 22:42 ` [PATCH 1/9] nfp: Call FIELD_PREP() in NFP_ETH_SET_BIT_CONFIG() wrapper david.laight.linux
@ 2025-12-08 22:42 ` david.laight.linux
2025-12-08 22:56 ` Greg KH
2025-12-08 22:42 ` [PATCH 3/9] bitmap: Use FIELD_PREP() in expansion of FIELD_PREP_WM16() david.laight.linux
` (7 subsequent siblings)
9 siblings, 1 reply; 23+ messages in thread
From: david.laight.linux @ 2025-12-08 22:42 UTC (permalink / raw)
To: Yury Norov, Rasmus Villemoes, linux-kernel, linux-usb,
Geert Uytterhoeven
Cc: David Laight
From: David Laight <david.laight.linux@gmail.com>
FIELD_GET needs to use __auto_type to get the value of the 'reg'
parameter, this can't be used with bifields.
FIELD_GET also want to verify the size of 'reg' so can't add zero
to force the type to int.
So add a zero here.
Signed-off-by: David Laight <david.laight.linux@gmail.com>
---
drivers/thunderbolt/tb.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index e96474f17067..7ca2b5a0f01e 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -1307,7 +1307,7 @@ static inline struct tb_retimer *tb_to_retimer(struct device *dev)
*/
static inline unsigned int usb4_switch_version(const struct tb_switch *sw)
{
- return FIELD_GET(USB4_VERSION_MAJOR_MASK, sw->config.thunderbolt_version);
+ return FIELD_GET(USB4_VERSION_MAJOR_MASK, sw->config.thunderbolt_version + 0);
}
/**
--
2.39.5
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 3/9] bitmap: Use FIELD_PREP() in expansion of FIELD_PREP_WM16()
2025-12-08 22:42 [PATCH 0/9] bitfield: tidy up bitfield.h david.laight.linux
2025-12-08 22:42 ` [PATCH 1/9] nfp: Call FIELD_PREP() in NFP_ETH_SET_BIT_CONFIG() wrapper david.laight.linux
2025-12-08 22:42 ` [PATCH 2/9] thunderblot: Don't pass a bitfield to FIELD_GET david.laight.linux
@ 2025-12-08 22:42 ` david.laight.linux
2025-12-09 0:54 ` Yury Norov
2025-12-08 22:42 ` [PATCH 4/9] bitfield: Copy #define parameters to locals david.laight.linux
` (6 subsequent siblings)
9 siblings, 1 reply; 23+ messages in thread
From: david.laight.linux @ 2025-12-08 22:42 UTC (permalink / raw)
To: Yury Norov, Rasmus Villemoes, linux-kernel, linux-usb,
Geert Uytterhoeven
Cc: David Laight
From: David Laight <david.laight.linux@gmail.com>
Instead of directly expanding __BF_FIELD_CHECK() (which really ought
not be used outside bitfield) and open-coding the generation of the
masked value, just call FIELD_PREP() and add an extra check for
the mask being at most 16 bits.
Signed-off-by: David Laight <david.laight.linux@gmail.com>
---
include/linux/hw_bitfield.h | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/include/linux/hw_bitfield.h b/include/linux/hw_bitfield.h
index df202e167ce4..d7f21b60449b 100644
--- a/include/linux/hw_bitfield.h
+++ b/include/linux/hw_bitfield.h
@@ -23,15 +23,14 @@
* register, a bit in the lower half is only updated if the corresponding bit
* in the upper half is high.
*/
-#define FIELD_PREP_WM16(_mask, _val) \
- ({ \
- typeof(_val) __val = _val; \
- typeof(_mask) __mask = _mask; \
- __BF_FIELD_CHECK(__mask, ((u16)0U), __val, \
- "HWORD_UPDATE: "); \
- (((typeof(__mask))(__val) << __bf_shf(__mask)) & (__mask)) | \
- ((__mask) << 16); \
- })
+#define FIELD_PREP_WM16(mask, val) \
+({ \
+ __auto_type _mask = mask; \
+ u32 _val = FIELD_PREP(_mask, val); \
+ BUILD_BUG_ON_MSG(_mask > 0xffffu, \
+ "FIELD_PREP_WM16: mask too large"); \
+ _val | (_mask << 16); \
+})
/**
* FIELD_PREP_WM16_CONST() - prepare a constant bitfield element with a mask in
--
2.39.5
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 4/9] bitfield: Copy #define parameters to locals
2025-12-08 22:42 [PATCH 0/9] bitfield: tidy up bitfield.h david.laight.linux
` (2 preceding siblings ...)
2025-12-08 22:42 ` [PATCH 3/9] bitmap: Use FIELD_PREP() in expansion of FIELD_PREP_WM16() david.laight.linux
@ 2025-12-08 22:42 ` david.laight.linux
2025-12-08 22:42 ` [PATCH 5/9] bitfield: FIELD_MODIFY: Only do a single read/write on the target david.laight.linux
` (5 subsequent siblings)
9 siblings, 0 replies; 23+ messages in thread
From: david.laight.linux @ 2025-12-08 22:42 UTC (permalink / raw)
To: Yury Norov, Rasmus Villemoes, linux-kernel, linux-usb,
Geert Uytterhoeven
Cc: David Laight
From: David Laight <david.laight.linux@gmail.com>
Use __auto_type to take copies of parameters to both ensure they are
evaluated only once and to avoid bloating the pre-processor output.
In particular 'mask' is likely to be GENMASK() and the expension
of FIELD_GET() is then about 18KB.
Remove any extra (), update kerneldoc.
Consistently use xxx for #define formal parameters and _xxx for
local variables.
Rather than use (typeof(mask))(val) to ensure bits aren't lost when
val is shifted left, use '__auto_type _val = 1 ? (val) : _mask;'
relying on the ?: operator to generate a type that is large enough.
Remove the (typeof(mask)) cast from __FIELD_GET(), it can only make
a difference if 'reg' is larger than 'mask' and the caller cares about
the actual type.
Note that mask usually comes from GENMASK() and is then 'unsigned long'.
Rename the internal defines __FIELD_PREP to __BF_FIELD_PREP and
__FIELD_GET to __BF_FIELD_GET.
Now that field_prep() and field_get() copy their parameters there is
no need for the __field_prep() and __field_get() defines.
But add a define to generate the required 'shift' to use in both defines.
Signed-off-by: David Laight <david.laight.linux@gmail.com>
---
include/linux/bitfield.h | 150 ++++++++++++++++++++-------------------
1 file changed, 78 insertions(+), 72 deletions(-)
diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
index 126dc5b380af..3e013da9ea12 100644
--- a/include/linux/bitfield.h
+++ b/include/linux/bitfield.h
@@ -61,17 +61,17 @@
#define __bf_cast_unsigned(type, x) ((__unsigned_scalar_typeof(type))(x))
-#define __BF_FIELD_CHECK_MASK(_mask, _val, _pfx) \
+#define __BF_FIELD_CHECK_MASK(mask, val, pfx) \
({ \
- BUILD_BUG_ON_MSG(!__builtin_constant_p(_mask), \
- _pfx "mask is not constant"); \
- BUILD_BUG_ON_MSG((_mask) == 0, _pfx "mask is zero"); \
- BUILD_BUG_ON_MSG(__builtin_constant_p(_val) ? \
- ~((_mask) >> __bf_shf(_mask)) & \
- (0 + (_val)) : 0, \
- _pfx "value too large for the field"); \
- __BUILD_BUG_ON_NOT_POWER_OF_2((_mask) + \
- (1ULL << __bf_shf(_mask))); \
+ BUILD_BUG_ON_MSG(!__builtin_constant_p(mask), \
+ pfx "mask is not constant"); \
+ BUILD_BUG_ON_MSG((mask) == 0, _pfx "mask is zero"); \
+ BUILD_BUG_ON_MSG(__builtin_constant_p(val) ? \
+ ~((mask) >> __bf_shf(mask)) & \
+ (0 + (val)) : 0, \
+ pfx "value too large for the field"); \
+ __BUILD_BUG_ON_NOT_POWER_OF_2((mask) + \
+ (1ULL << __bf_shf(mask))); \
})
#define __BF_FIELD_CHECK_REG(mask, reg, pfx) \
@@ -85,64 +85,69 @@
__BF_FIELD_CHECK_REG(mask, reg, pfx); \
})
-#define __FIELD_PREP(mask, val, pfx) \
+#define __BF_FIELD_PREP(mask, val, pfx) \
({ \
__BF_FIELD_CHECK_MASK(mask, val, pfx); \
- ((typeof(mask))(val) << __bf_shf(mask)) & (mask); \
+ ((val) << __bf_shf(mask)) & (mask); \
})
-#define __FIELD_GET(mask, reg, pfx) \
+#define __BF_FIELD_GET(mask, reg, pfx) \
({ \
__BF_FIELD_CHECK_MASK(mask, 0U, pfx); \
- (typeof(mask))(((reg) & (mask)) >> __bf_shf(mask)); \
+ ((reg) & (mask)) >> __bf_shf(mask); \
})
/**
* FIELD_MAX() - produce the maximum value representable by a field
- * @_mask: shifted mask defining the field's length and position
+ * @mask: shifted mask defining the field's length and position
*
* FIELD_MAX() returns the maximum value that can be held in the field
- * specified by @_mask.
+ * specified by @mask.
*/
-#define FIELD_MAX(_mask) \
+#define FIELD_MAX(mask) \
({ \
+ __auto_type _mask = mask; \
__BF_FIELD_CHECK(_mask, 0ULL, 0ULL, "FIELD_MAX: "); \
- (typeof(_mask))((_mask) >> __bf_shf(_mask)); \
+ (_mask >> __bf_shf(_mask)); \
})
/**
* FIELD_FIT() - check if value fits in the field
- * @_mask: shifted mask defining the field's length and position
- * @_val: value to test against the field
+ * @mask: shifted mask defining the field's length and position
+ * @val: value to test against the field
*
- * Return: true if @_val can fit inside @_mask, false if @_val is too big.
+ * Return: true if @val can fit inside @mask, false if @val is too big.
*/
-#define FIELD_FIT(_mask, _val) \
+#define FIELD_FIT(mask, val) \
({ \
+ __auto_type _mask = mask; \
+ __auto_type _val = 1 ? (val) : _mask; \
__BF_FIELD_CHECK(_mask, 0ULL, 0ULL, "FIELD_FIT: "); \
- !((((typeof(_mask))_val) << __bf_shf(_mask)) & ~(_mask)); \
+ !((_val << __bf_shf(_mask)) & ~_mask); \
})
/**
* FIELD_PREP() - prepare a bitfield element
- * @_mask: shifted mask defining the field's length and position
- * @_val: value to put in the field
+ * @mask: shifted mask defining the field's length and position
+ * @val: value to put in the field
*
* FIELD_PREP() masks and shifts up the value. The result should
* be combined with other fields of the bitfield using logical OR.
*/
-#define FIELD_PREP(_mask, _val) \
+#define FIELD_PREP(mask, val) \
({ \
+ __auto_type _mask = mask; \
+ __auto_type _val = 1 ? (val) : _mask; \
__BF_FIELD_CHECK_REG(_mask, 0ULL, "FIELD_PREP: "); \
- __FIELD_PREP(_mask, _val, "FIELD_PREP: "); \
+ __BF_FIELD_PREP(_mask, _val, "FIELD_PREP: "); \
})
#define __BF_CHECK_POW2(n) BUILD_BUG_ON_ZERO(((n) & ((n) - 1)) != 0)
/**
* FIELD_PREP_CONST() - prepare a constant bitfield element
- * @_mask: shifted mask defining the field's length and position
- * @_val: value to put in the field
+ * @mask: shifted mask defining the field's length and position
+ * @val: value to put in the field
*
* FIELD_PREP_CONST() masks and shifts up the value. The result should
* be combined with other fields of the bitfield using logical OR.
@@ -151,47 +156,52 @@
* be used in initializers. Error checking is less comfortable for this
* version, and non-constant masks cannot be used.
*/
-#define FIELD_PREP_CONST(_mask, _val) \
+#define FIELD_PREP_CONST(mask, val) \
( \
/* mask must be non-zero */ \
- BUILD_BUG_ON_ZERO((_mask) == 0) + \
+ BUILD_BUG_ON_ZERO((mask) == 0) + \
/* check if value fits */ \
- BUILD_BUG_ON_ZERO(~((_mask) >> __bf_shf(_mask)) & (_val)) + \
+ BUILD_BUG_ON_ZERO(~((mask) >> __bf_shf(mask)) & (val)) + \
/* check if mask is contiguous */ \
- __BF_CHECK_POW2((_mask) + (1ULL << __bf_shf(_mask))) + \
+ __BF_CHECK_POW2((mask) + (1ULL << __bf_shf(mask))) + \
/* and create the value */ \
- (((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask)) \
+ (((typeof(mask))(val) << __bf_shf(mask)) & (mask)) \
)
/**
* FIELD_GET() - extract a bitfield element
- * @_mask: shifted mask defining the field's length and position
- * @_reg: value of entire bitfield
+ * @mask: shifted mask defining the field's length and position
+ * @reg: value of entire bitfield
*
- * FIELD_GET() extracts the field specified by @_mask from the
- * bitfield passed in as @_reg by masking and shifting it down.
+ * FIELD_GET() extracts the field specified by @mask from the
+ * bitfield passed in as @reg by masking and shifting it down.
*/
-#define FIELD_GET(_mask, _reg) \
+#define FIELD_GET(mask, reg) \
({ \
+ __auto_type _mask = mask; \
+ __auto_type _reg = reg; \
__BF_FIELD_CHECK_REG(_mask, _reg, "FIELD_GET: "); \
- __FIELD_GET(_mask, _reg, "FIELD_GET: "); \
+ __BF_FIELD_GET(_mask, _reg, "FIELD_GET: "); \
})
/**
* FIELD_MODIFY() - modify a bitfield element
- * @_mask: shifted mask defining the field's length and position
- * @_reg_p: pointer to the memory that should be updated
- * @_val: value to store in the bitfield
+ * @mask: shifted mask defining the field's length and position
+ * @reg_p: pointer to the memory that should be updated
+ * @val: value to store in the bitfield
*
- * FIELD_MODIFY() modifies the set of bits in @_reg_p specified by @_mask,
- * by replacing them with the bitfield value passed in as @_val.
+ * FIELD_MODIFY() modifies the set of bits in @reg_p specified by @mask,
+ * by replacing them with the bitfield value passed in as @val.
*/
-#define FIELD_MODIFY(_mask, _reg_p, _val) \
+#define FIELD_MODIFY(mask, reg_p, val) \
({ \
+ __auto_type _mask = mask; \
+ __auto_type _reg_p = reg_p; \
+ __auto_type _val = 1 ? (val) : _mask; \
typecheck_pointer(_reg_p); \
- __BF_FIELD_CHECK(_mask, *(_reg_p), _val, "FIELD_MODIFY: "); \
- *(_reg_p) &= ~(_mask); \
- *(_reg_p) |= (((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask)); \
+ __BF_FIELD_CHECK(_mask, *_reg_p, _val, "FIELD_MODIFY: "); \
+ *_reg_p &= ~_mask; \
+ *_reg_p |= ((_val << __bf_shf(_mask)) & _mask); \
})
extern void __compiletime_error("value doesn't fit into mask")
@@ -241,23 +251,9 @@ __MAKE_OP(64)
#undef __MAKE_OP
#undef ____MAKE_OP
-#define __field_prep(mask, val) \
- ({ \
- __auto_type __mask = (mask); \
- typeof(__mask) __val = (val); \
- unsigned int __shift = BITS_PER_TYPE(__mask) <= 32 ? \
- __ffs(__mask) : __ffs64(__mask); \
- (__val << __shift) & __mask; \
- })
-
-#define __field_get(mask, reg) \
- ({ \
- __auto_type __mask = (mask); \
- typeof(__mask) __reg = (reg); \
- unsigned int __shift = BITS_PER_TYPE(__mask) <= 32 ? \
- __ffs(__mask) : __ffs64(__mask); \
- (__reg & __mask) >> __shift; \
- })
+/* As __bf_shf() but for non-zero variables */
+#define __BF_SHIFT(mask) \
+ (BITS_PER_TYPE(_mask) <= 32 ? __ffs(_mask) : __ffs64(_mask))
/**
* field_prep() - prepare a bitfield element
@@ -275,9 +271,14 @@ __MAKE_OP(64)
* If you want to ensure that @mask is a compile-time constant, please use
* FIELD_PREP() directly instead.
*/
-#define field_prep(mask, val) \
- (__builtin_constant_p(mask) ? __FIELD_PREP(mask, val, "field_prep: ") \
- : __field_prep(mask, val))
+#define field_prep(mask, val) \
+({ \
+ __auto_type _mask = mask; \
+ __auto_type _val = 1 ? (val) : _mask; \
+ __builtin_constant_p(_mask) ? \
+ __BF_FIELD_PREP(_mask, _val, "field_prep: ") : \
+ (_val << __BF_SHIFT(_mask)) & _mask; \
+})
/**
* field_get() - extract a bitfield element
@@ -295,8 +296,13 @@ __MAKE_OP(64)
* If you want to ensure that @mask is a compile-time constant, please use
* FIELD_GET() directly instead.
*/
-#define field_get(mask, reg) \
- (__builtin_constant_p(mask) ? __FIELD_GET(mask, reg, "field_get: ") \
- : __field_get(mask, reg))
+#define field_get(mask, reg) \
+({ \
+ __auto_type _mask = mask; \
+ __auto_type _reg = reg; \
+ __builtin_constant_p(_mask) ? \
+ __BF_FIELD_GET(_mask, _reg, "field_get: ") : \
+ (_reg & _mask) >> __BF_SHIFT(_mask); \
+})
#endif
--
2.39.5
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 5/9] bitfield: FIELD_MODIFY: Only do a single read/write on the target
2025-12-08 22:42 [PATCH 0/9] bitfield: tidy up bitfield.h david.laight.linux
` (3 preceding siblings ...)
2025-12-08 22:42 ` [PATCH 4/9] bitfield: Copy #define parameters to locals david.laight.linux
@ 2025-12-08 22:42 ` david.laight.linux
2025-12-08 22:42 ` [PATCH 6/9] bitfield: Update sanity checks david.laight.linux
` (4 subsequent siblings)
9 siblings, 0 replies; 23+ messages in thread
From: david.laight.linux @ 2025-12-08 22:42 UTC (permalink / raw)
To: Yury Norov, Rasmus Villemoes, linux-kernel, linux-usb,
Geert Uytterhoeven
Cc: David Laight
From: David Laight <david.laight.linux@gmail.com>
Replace the:
*reg &= ~mask; *reg |= new_value;
with a single assignment.
While the compiler will usually optimise the extra access away
it isn't guaranteed.
Signed-off-by: David Laight <david.laight.linux@gmail.com>
---
include/linux/bitfield.h | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
index 3e013da9ea12..3e0e8533bb66 100644
--- a/include/linux/bitfield.h
+++ b/include/linux/bitfield.h
@@ -200,8 +200,7 @@
__auto_type _val = 1 ? (val) : _mask; \
typecheck_pointer(_reg_p); \
__BF_FIELD_CHECK(_mask, *_reg_p, _val, "FIELD_MODIFY: "); \
- *_reg_p &= ~_mask; \
- *_reg_p |= ((_val << __bf_shf(_mask)) & _mask); \
+ *_reg_p = (*_reg_p & ~_mask) | ((_val << __bf_shf(_mask)) & _mask); \
})
extern void __compiletime_error("value doesn't fit into mask")
--
2.39.5
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 6/9] bitfield: Update sanity checks
2025-12-08 22:42 [PATCH 0/9] bitfield: tidy up bitfield.h david.laight.linux
` (4 preceding siblings ...)
2025-12-08 22:42 ` [PATCH 5/9] bitfield: FIELD_MODIFY: Only do a single read/write on the target david.laight.linux
@ 2025-12-08 22:42 ` david.laight.linux
2025-12-08 22:42 ` [PATCH 7/9] bitfield: Reduce indentation david.laight.linux
` (3 subsequent siblings)
9 siblings, 0 replies; 23+ messages in thread
From: david.laight.linux @ 2025-12-08 22:42 UTC (permalink / raw)
To: Yury Norov, Rasmus Villemoes, linux-kernel, linux-usb,
Geert Uytterhoeven
Cc: David Laight
From: David Laight <david.laight.linux@gmail.com>
Simplify the check for 'reg' being large enough to hold 'mask' using
sizeof (reg) rather than a convoluted scheme to generate an unsigned
type the same size as 'reg'.
There are three places where the mask is checked for being non-zero
and contiguous. Add a simple expression that checks it and use in
all three places.
Three of the five calls to __BF_FIELD_CHECK_MASK() don't have a 'value'
to check, separate out as was done to __BF_FIELD_CHECK_REG().
There is no point checking a 'val' of zero or a 'reg' of 0ULL (both
are placeholders) - remove/change the calls.
There should be a check of __BF_FIELD_CHECK_REG() when __BF_FIELD_GET()
is called from field_get().
Move the check from FIELD_GET() into __BF_FIELD_GET().
Delete the now-unused __BF_FIELD_CHECK().
Signed-off-by: David Laight <david.laight.linux@gmail.com>
---
include/linux/bitfield.h | 74 ++++++++++++++--------------------------
1 file changed, 26 insertions(+), 48 deletions(-)
diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
index 3e0e8533bb66..7e8d436b6571 100644
--- a/include/linux/bitfield.h
+++ b/include/linux/bitfield.h
@@ -45,55 +45,38 @@
#define __bf_shf(x) (__builtin_ffsll(x) - 1)
-#define __scalar_type_to_unsigned_cases(type) \
- unsigned type: (unsigned type)0, \
- signed type: (unsigned type)0
+#define __BF_VALIDATE_MASK(mask) \
+ (!(mask) || ((mask) & ((mask) + ((mask) & -(mask)))))
-#define __unsigned_scalar_typeof(x) typeof( \
- _Generic((x), \
- char: (unsigned char)0, \
- __scalar_type_to_unsigned_cases(char), \
- __scalar_type_to_unsigned_cases(short), \
- __scalar_type_to_unsigned_cases(int), \
- __scalar_type_to_unsigned_cases(long), \
- __scalar_type_to_unsigned_cases(long long), \
- default: (x)))
-
-#define __bf_cast_unsigned(type, x) ((__unsigned_scalar_typeof(type))(x))
-
-#define __BF_FIELD_CHECK_MASK(mask, val, pfx) \
- ({ \
+#define __BF_FIELD_CHECK_MASK(mask, pfx) \
+ do { \
BUILD_BUG_ON_MSG(!__builtin_constant_p(mask), \
pfx "mask is not constant"); \
- BUILD_BUG_ON_MSG((mask) == 0, _pfx "mask is zero"); \
- BUILD_BUG_ON_MSG(__builtin_constant_p(val) ? \
- ~((mask) >> __bf_shf(mask)) & \
- (0 + (val)) : 0, \
- pfx "value too large for the field"); \
- __BUILD_BUG_ON_NOT_POWER_OF_2((mask) + \
- (1ULL << __bf_shf(mask))); \
- })
+ BUILD_BUG_ON_MSG(__BF_VALIDATE_MASK(mask), \
+ pfx "mask is zero or not contiguous"); \
+ } while (0)
+
+#define __BF_FIELD_CHECK_VAL(mask, val, pfx) \
+ BUILD_BUG_ON_MSG(__builtin_constant_p(val) && \
+ ~((mask) >> __bf_shf(mask)) & (val), \
+ pfx "value too large for the field")
#define __BF_FIELD_CHECK_REG(mask, reg, pfx) \
- BUILD_BUG_ON_MSG(__bf_cast_unsigned(mask, mask) > \
- __bf_cast_unsigned(reg, ~0ull), \
+ BUILD_BUG_ON_MSG(mask + 0U + 0UL + 0ULL > \
+ ~0ULL >> (64 - 8 * sizeof (reg)), \
pfx "type of reg too small for mask")
-#define __BF_FIELD_CHECK(mask, reg, val, pfx) \
- ({ \
- __BF_FIELD_CHECK_MASK(mask, val, pfx); \
- __BF_FIELD_CHECK_REG(mask, reg, pfx); \
- })
-
#define __BF_FIELD_PREP(mask, val, pfx) \
({ \
- __BF_FIELD_CHECK_MASK(mask, val, pfx); \
+ __BF_FIELD_CHECK_MASK(mask, pfx); \
+ __BF_FIELD_CHECK_VAL(mask, val, pfx); \
((val) << __bf_shf(mask)) & (mask); \
})
#define __BF_FIELD_GET(mask, reg, pfx) \
({ \
- __BF_FIELD_CHECK_MASK(mask, 0U, pfx); \
+ __BF_FIELD_CHECK_MASK(mask, pfx); \
+ __BF_FIELD_CHECK_REG(mask, reg, pfx); \
((reg) & (mask)) >> __bf_shf(mask); \
})
@@ -107,7 +90,7 @@
#define FIELD_MAX(mask) \
({ \
__auto_type _mask = mask; \
- __BF_FIELD_CHECK(_mask, 0ULL, 0ULL, "FIELD_MAX: "); \
+ __BF_FIELD_CHECK_MASK(_mask, "FIELD_MAX: "); \
(_mask >> __bf_shf(_mask)); \
})
@@ -122,7 +105,7 @@
({ \
__auto_type _mask = mask; \
__auto_type _val = 1 ? (val) : _mask; \
- __BF_FIELD_CHECK(_mask, 0ULL, 0ULL, "FIELD_FIT: "); \
+ __BF_FIELD_CHECK_MASK(_mask, "FIELD_FIT: "); \
!((_val << __bf_shf(_mask)) & ~_mask); \
})
@@ -138,12 +121,9 @@
({ \
__auto_type _mask = mask; \
__auto_type _val = 1 ? (val) : _mask; \
- __BF_FIELD_CHECK_REG(_mask, 0ULL, "FIELD_PREP: "); \
__BF_FIELD_PREP(_mask, _val, "FIELD_PREP: "); \
})
-#define __BF_CHECK_POW2(n) BUILD_BUG_ON_ZERO(((n) & ((n) - 1)) != 0)
-
/**
* FIELD_PREP_CONST() - prepare a constant bitfield element
* @mask: shifted mask defining the field's length and position
@@ -158,12 +138,10 @@
*/
#define FIELD_PREP_CONST(mask, val) \
( \
- /* mask must be non-zero */ \
- BUILD_BUG_ON_ZERO((mask) == 0) + \
+ /* mask must be non-zero and contiguous */ \
+ BUILD_BUG_ON_ZERO(__BF_VALIDATE_MASK(mask)) + \
/* check if value fits */ \
BUILD_BUG_ON_ZERO(~((mask) >> __bf_shf(mask)) & (val)) + \
- /* check if mask is contiguous */ \
- __BF_CHECK_POW2((mask) + (1ULL << __bf_shf(mask))) + \
/* and create the value */ \
(((typeof(mask))(val) << __bf_shf(mask)) & (mask)) \
)
@@ -180,7 +158,6 @@
({ \
__auto_type _mask = mask; \
__auto_type _reg = reg; \
- __BF_FIELD_CHECK_REG(_mask, _reg, "FIELD_GET: "); \
__BF_FIELD_GET(_mask, _reg, "FIELD_GET: "); \
})
@@ -198,8 +175,9 @@
__auto_type _mask = mask; \
__auto_type _reg_p = reg_p; \
__auto_type _val = 1 ? (val) : _mask; \
- typecheck_pointer(_reg_p); \
- __BF_FIELD_CHECK(_mask, *_reg_p, _val, "FIELD_MODIFY: "); \
+ __BF_FIELD_CHECK_MASK(_mask, "FIELD_MODIFY: "); \
+ __BF_FIELD_CHECK_VAL(_mask, _val, "FIELD_MODIFY: "); \
+ __BF_FIELD_CHECK_REG(_mask, *_reg_p, "FIELD_MODIFY: "); \
*_reg_p = (*_reg_p & ~_mask) | ((_val << __bf_shf(_mask)) & _mask); \
})
@@ -209,7 +187,7 @@ 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))
+ if (__BF_VALIDATE_MASK(field))
__bad_mask();
return field & -field;
}
--
2.39.5
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 7/9] bitfield: Reduce indentation
2025-12-08 22:42 [PATCH 0/9] bitfield: tidy up bitfield.h david.laight.linux
` (5 preceding siblings ...)
2025-12-08 22:42 ` [PATCH 6/9] bitfield: Update sanity checks david.laight.linux
@ 2025-12-08 22:42 ` david.laight.linux
2025-12-08 22:42 ` [PATCH 8/9] bitfield: Add comment block for the host/fixed endian functions david.laight.linux
` (2 subsequent siblings)
9 siblings, 0 replies; 23+ messages in thread
From: david.laight.linux @ 2025-12-08 22:42 UTC (permalink / raw)
To: Yury Norov, Rasmus Villemoes, linux-kernel, linux-usb,
Geert Uytterhoeven
Cc: David Laight
From: David Laight <david.laight.linux@gmail.com>
There is no need to double indent the body of #defines.
Leave the opening ( and closing ) on their own lines.
Delete extra tabs before continuation markers.
Signed-off-by: David Laight <david.laight.linux@gmail.com>
---
include/linux/bitfield.h | 132 +++++++++++++++++++--------------------
1 file changed, 66 insertions(+), 66 deletions(-)
diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
index 7e8d436b6571..bfd80ebd25b1 100644
--- a/include/linux/bitfield.h
+++ b/include/linux/bitfield.h
@@ -48,37 +48,37 @@
#define __BF_VALIDATE_MASK(mask) \
(!(mask) || ((mask) & ((mask) + ((mask) & -(mask)))))
-#define __BF_FIELD_CHECK_MASK(mask, pfx) \
- do { \
- BUILD_BUG_ON_MSG(!__builtin_constant_p(mask), \
- pfx "mask is not constant"); \
- BUILD_BUG_ON_MSG(__BF_VALIDATE_MASK(mask), \
- pfx "mask is zero or not contiguous"); \
- } while (0)
+#define __BF_FIELD_CHECK_MASK(mask, pfx) \
+do { \
+ BUILD_BUG_ON_MSG(!__builtin_constant_p(mask), \
+ pfx "mask is not constant"); \
+ BUILD_BUG_ON_MSG(__BF_VALIDATE_MASK(mask), \
+ pfx "mask is zero or not contiguous"); \
+} while (0)
#define __BF_FIELD_CHECK_VAL(mask, val, pfx) \
BUILD_BUG_ON_MSG(__builtin_constant_p(val) && \
~((mask) >> __bf_shf(mask)) & (val), \
pfx "value too large for the field")
-#define __BF_FIELD_CHECK_REG(mask, reg, pfx) \
- BUILD_BUG_ON_MSG(mask + 0U + 0UL + 0ULL > \
- ~0ULL >> (64 - 8 * sizeof (reg)), \
+#define __BF_FIELD_CHECK_REG(mask, reg, pfx) \
+ BUILD_BUG_ON_MSG(mask + 0U + 0UL + 0ULL > \
+ ~0ULL >> (64 - 8 * sizeof (reg)), \
pfx "type of reg too small for mask")
-#define __BF_FIELD_PREP(mask, val, pfx) \
- ({ \
- __BF_FIELD_CHECK_MASK(mask, pfx); \
- __BF_FIELD_CHECK_VAL(mask, val, pfx); \
- ((val) << __bf_shf(mask)) & (mask); \
- })
+#define __BF_FIELD_PREP(mask, val, pfx) \
+({ \
+ __BF_FIELD_CHECK_MASK(mask, pfx); \
+ __BF_FIELD_CHECK_VAL(mask, val, pfx); \
+ ((val) << __bf_shf(mask)) & (mask); \
+})
-#define __BF_FIELD_GET(mask, reg, pfx) \
- ({ \
- __BF_FIELD_CHECK_MASK(mask, pfx); \
- __BF_FIELD_CHECK_REG(mask, reg, pfx); \
- ((reg) & (mask)) >> __bf_shf(mask); \
- })
+#define __BF_FIELD_GET(mask, reg, pfx) \
+({ \
+ __BF_FIELD_CHECK_MASK(mask, pfx); \
+ __BF_FIELD_CHECK_REG(mask, reg, pfx); \
+ ((reg) & (mask)) >> __bf_shf(mask); \
+})
/**
* FIELD_MAX() - produce the maximum value representable by a field
@@ -87,12 +87,12 @@
* FIELD_MAX() returns the maximum value that can be held in the field
* specified by @mask.
*/
-#define FIELD_MAX(mask) \
- ({ \
- __auto_type _mask = mask; \
- __BF_FIELD_CHECK_MASK(_mask, "FIELD_MAX: "); \
- (_mask >> __bf_shf(_mask)); \
- })
+#define FIELD_MAX(mask) \
+({ \
+ __auto_type _mask = mask; \
+ __BF_FIELD_CHECK_MASK(_mask, "FIELD_MAX: "); \
+ (_mask >> __bf_shf(_mask)); \
+})
/**
* FIELD_FIT() - check if value fits in the field
@@ -101,13 +101,13 @@
*
* Return: true if @val can fit inside @mask, false if @val is too big.
*/
-#define FIELD_FIT(mask, val) \
- ({ \
- __auto_type _mask = mask; \
- __auto_type _val = 1 ? (val) : _mask; \
- __BF_FIELD_CHECK_MASK(_mask, "FIELD_FIT: "); \
- !((_val << __bf_shf(_mask)) & ~_mask); \
- })
+#define FIELD_FIT(mask, val) \
+({ \
+ __auto_type _mask = mask; \
+ __auto_type _val = 1 ? (val) : _mask; \
+ __BF_FIELD_CHECK_MASK(_mask, "FIELD_FIT: "); \
+ !((_val << __bf_shf(_mask)) & ~_mask); \
+})
/**
* FIELD_PREP() - prepare a bitfield element
@@ -117,12 +117,12 @@
* FIELD_PREP() masks and shifts up the value. The result should
* be combined with other fields of the bitfield using logical OR.
*/
-#define FIELD_PREP(mask, val) \
- ({ \
- __auto_type _mask = mask; \
- __auto_type _val = 1 ? (val) : _mask; \
- __BF_FIELD_PREP(_mask, _val, "FIELD_PREP: "); \
- })
+#define FIELD_PREP(mask, val) \
+({ \
+ __auto_type _mask = mask; \
+ __auto_type _val = 1 ? (val) : _mask; \
+ __BF_FIELD_PREP(_mask, _val, "FIELD_PREP: "); \
+})
/**
* FIELD_PREP_CONST() - prepare a constant bitfield element
@@ -136,15 +136,15 @@
* be used in initializers. Error checking is less comfortable for this
* version, and non-constant masks cannot be used.
*/
-#define FIELD_PREP_CONST(mask, val) \
- ( \
- /* mask must be non-zero and contiguous */ \
- BUILD_BUG_ON_ZERO(__BF_VALIDATE_MASK(mask)) + \
- /* check if value fits */ \
- BUILD_BUG_ON_ZERO(~((mask) >> __bf_shf(mask)) & (val)) + \
- /* and create the value */ \
- (((typeof(mask))(val) << __bf_shf(mask)) & (mask)) \
- )
+#define FIELD_PREP_CONST(mask, val) \
+( \
+ /* mask must be non-zero and contiguous */ \
+ BUILD_BUG_ON_ZERO(__BF_VALIDATE_MASK(mask)) + \
+ /* check if value fits */ \
+ BUILD_BUG_ON_ZERO(~((mask) >> __bf_shf(mask)) & (val)) + \
+ /* and create the value */ \
+ (((typeof(mask))(val) << __bf_shf(mask)) & (mask)) \
+)
/**
* FIELD_GET() - extract a bitfield element
@@ -154,12 +154,12 @@
* FIELD_GET() extracts the field specified by @mask from the
* bitfield passed in as @reg by masking and shifting it down.
*/
-#define FIELD_GET(mask, reg) \
- ({ \
- __auto_type _mask = mask; \
- __auto_type _reg = reg; \
- __BF_FIELD_GET(_mask, _reg, "FIELD_GET: "); \
- })
+#define FIELD_GET(mask, reg) \
+({ \
+ __auto_type _mask = mask; \
+ __auto_type _reg = reg; \
+ __BF_FIELD_GET(_mask, _reg, "FIELD_GET: "); \
+})
/**
* FIELD_MODIFY() - modify a bitfield element
@@ -170,16 +170,16 @@
* FIELD_MODIFY() modifies the set of bits in @reg_p specified by @mask,
* by replacing them with the bitfield value passed in as @val.
*/
-#define FIELD_MODIFY(mask, reg_p, val) \
- ({ \
- __auto_type _mask = mask; \
- __auto_type _reg_p = reg_p; \
- __auto_type _val = 1 ? (val) : _mask; \
- __BF_FIELD_CHECK_MASK(_mask, "FIELD_MODIFY: "); \
- __BF_FIELD_CHECK_VAL(_mask, _val, "FIELD_MODIFY: "); \
- __BF_FIELD_CHECK_REG(_mask, *_reg_p, "FIELD_MODIFY: "); \
- *_reg_p = (*_reg_p & ~_mask) | ((_val << __bf_shf(_mask)) & _mask); \
- })
+#define FIELD_MODIFY(mask, reg_p, val) \
+({ \
+ __auto_type _mask = mask; \
+ __auto_type _reg_p = reg_p; \
+ __auto_type _val = 1 ? (val) : _mask; \
+ __BF_FIELD_CHECK_MASK(_mask, "FIELD_MODIFY: "); \
+ __BF_FIELD_CHECK_VAL(_mask, _val, "FIELD_MODIFY: "); \
+ __BF_FIELD_CHECK_REG(_mask, *_reg_p, "FIELD_MODIFY: "); \
+ *_reg_p = (*_reg_p & ~_mask) | ((_val << __bf_shf(_mask)) & _mask); \
+})
extern void __compiletime_error("value doesn't fit into mask")
__field_overflow(void);
--
2.39.5
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 8/9] bitfield: Add comment block for the host/fixed endian functions
2025-12-08 22:42 [PATCH 0/9] bitfield: tidy up bitfield.h david.laight.linux
` (6 preceding siblings ...)
2025-12-08 22:42 ` [PATCH 7/9] bitfield: Reduce indentation david.laight.linux
@ 2025-12-08 22:42 ` david.laight.linux
2025-12-08 22:42 ` [PATCH 9/9] bitfield: Update comments for le/be functions david.laight.linux
2025-12-09 7:08 ` [PATCH 0/9] bitfield: tidy up bitfield.h Mika Westerberg
9 siblings, 0 replies; 23+ messages in thread
From: david.laight.linux @ 2025-12-08 22:42 UTC (permalink / raw)
To: Yury Norov, Rasmus Villemoes, linux-kernel, linux-usb,
Geert Uytterhoeven
Cc: David Laight
From: David Laight <david.laight.linux@gmail.com>
Copied almost verbatim from the commit message that added the functions.
Signed-off-by: David Laight <david.laight.linux@gmail.com>
---
include/linux/bitfield.h | 43 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
index bfd80ebd25b1..9feb489a8da3 100644
--- a/include/linux/bitfield.h
+++ b/include/linux/bitfield.h
@@ -181,6 +181,49 @@ do { \
*_reg_p = (*_reg_p & ~_mask) | ((_val << __bf_shf(_mask)) & _mask); \
})
+/*
+ * Primitives for manipulating bitfields both in host- and fixed-endian.
+ *
+ * * u32 le32_get_bits(__le32 val, u32 field) extracts the contents of the
+ * bitfield specified by @field in little-endian 32bit object @val and
+ * converts it to host-endian.
+ *
+ * * void le32p_replace_bits(__le32 *p, u32 v, u32 field) replaces
+ * the contents of the bitfield specified by @field in little-endian
+ * 32bit object pointed to by @p with the value of @v. New value is
+ * given in host-endian and stored as little-endian.
+ *
+ * * __le32 le32_replace_bits(__le32 old, u32 v, u32 field) is equivalent to
+ * ({__le32 tmp = old; le32p_replace_bits(&tmp, v, field); tmp;})
+ * In other words, instead of modifying an object in memory, it takes
+ * the initial value and returns the modified one.
+ *
+ * * __le32 le32_encode_bits(u32 v, u32 field) is equivalent to
+ * le32_replace_bits(0, v, field). In other words, it returns a little-endian
+ * 32bit object with the bitfield specified by @field containing the
+ * value of @v and all bits outside that bitfield being zero.
+ *
+ * Such set of helpers is defined for each of little-, big- and host-endian
+ * types; e.g. u64_get_bits(val, field) will return the contents of the bitfield
+ * specified by @field in host-endian 64bit object @val, etc. Of course, for
+ * host-endian no conversion is involved.
+ *
+ * Fields to access are specified as GENMASK() values - an N-bit field
+ * starting at bit #M is encoded as GENMASK(M + N - 1, M). Note that
+ * bit numbers refer to endianness of the object we are working with -
+ * e.g. GENMASK(11, 0) in __be16 refers to the second byte and the lower
+ * 4 bits of the first byte. In __le16 it would refer to the first byte
+ * and the lower 4 bits of the second byte, etc.
+ *
+ * Field specification must be a constant; __builtin_constant_p() doesn't
+ * have to be true for it, but compiler must be able to evaluate it at
+ * build time. If it cannot or if the value does not encode any bitfield,
+ * the build will fail.
+ *
+ * If the value being stored in a bitfield is a constant that does not fit
+ * into that bitfield, a warning will be generated at compile time.
+ */
+
extern void __compiletime_error("value doesn't fit into mask")
__field_overflow(void);
extern void __compiletime_error("bad bitfield mask")
--
2.39.5
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH 9/9] bitfield: Update comments for le/be functions
2025-12-08 22:42 [PATCH 0/9] bitfield: tidy up bitfield.h david.laight.linux
` (7 preceding siblings ...)
2025-12-08 22:42 ` [PATCH 8/9] bitfield: Add comment block for the host/fixed endian functions david.laight.linux
@ 2025-12-08 22:42 ` david.laight.linux
2025-12-09 7:08 ` [PATCH 0/9] bitfield: tidy up bitfield.h Mika Westerberg
9 siblings, 0 replies; 23+ messages in thread
From: david.laight.linux @ 2025-12-08 22:42 UTC (permalink / raw)
To: Yury Norov, Rasmus Villemoes, linux-kernel, linux-usb,
Geert Uytterhoeven
Cc: David Laight
From: David Laight <david.laight.linux@gmail.com>
Make it clear the the values are converted to host order before
being acted on.
Order the explantions with the simple functions first.
These still need converting to kerneldoc format.
Signed-off-by: David Laight <david.laight.linux@gmail.com>
---
include/linux/bitfield.h | 38 ++++++++++++++++++--------------------
1 file changed, 18 insertions(+), 20 deletions(-)
diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
index 9feb489a8da3..dcc4809b4706 100644
--- a/include/linux/bitfield.h
+++ b/include/linux/bitfield.h
@@ -184,24 +184,24 @@ do { \
/*
* Primitives for manipulating bitfields both in host- and fixed-endian.
*
- * * u32 le32_get_bits(__le32 val, u32 field) extracts the contents of the
- * bitfield specified by @field in little-endian 32bit object @val and
- * converts it to host-endian.
*
- * * void le32p_replace_bits(__le32 *p, u32 v, u32 field) replaces
- * the contents of the bitfield specified by @field in little-endian
- * 32bit object pointed to by @p with the value of @v. New value is
- * given in host-endian and stored as little-endian.
+ * * u32 le32_get_bits(__le32 val, u32 field) converts the little-endian 32bit
+ * object @val to host-endian then extracts the contents of the bitfield
+ * specified by @field.
+ *
+ * * __le32 le32_encode_bits(u32 v, u32 field) encodes the value of @v into
+ * the bitfield specified by @field then converts the value to little-endian.
+ * All the bits outside that bitfield being zero.
*
- * * __le32 le32_replace_bits(__le32 old, u32 v, u32 field) is equivalent to
- * ({__le32 tmp = old; le32p_replace_bits(&tmp, v, field); tmp;})
- * In other words, instead of modifying an object in memory, it takes
- * the initial value and returns the modified one.
+ * * __le32 le32_replace_bits(__le32 old, u32 v, u32 field) converts the
+ * little-endian 32bit object @old to host order, replaces the contents
+ * of the bitfield specified by @field with @v, then returns the value
+ * converted back to little-endian.
*
- * * __le32 le32_encode_bits(u32 v, u32 field) is equivalent to
- * le32_replace_bits(0, v, field). In other words, it returns a little-endian
- * 32bit object with the bitfield specified by @field containing the
- * value of @v and all bits outside that bitfield being zero.
+ * * void le32p_replace_bits(__le32 *p, u32 v, u32 field) replaces
+ * the contents of the bitfield specified by @field in little-endian
+ * 32bit object pointed to by @p with the value of @v.
+ * Equivalent to *p = le32_replace_bits(*p, v, field).
*
* Such set of helpers is defined for each of little-, big- and host-endian
* types; e.g. u64_get_bits(val, field) will return the contents of the bitfield
@@ -210,15 +210,13 @@ do { \
*
* Fields to access are specified as GENMASK() values - an N-bit field
* starting at bit #M is encoded as GENMASK(M + N - 1, M). Note that
- * bit numbers refer to endianness of the object we are working with -
+ * bit numbers refer to the value after being converted to host order -
* e.g. GENMASK(11, 0) in __be16 refers to the second byte and the lower
* 4 bits of the first byte. In __le16 it would refer to the first byte
* and the lower 4 bits of the second byte, etc.
*
- * Field specification must be a constant; __builtin_constant_p() doesn't
- * have to be true for it, but compiler must be able to evaluate it at
- * build time. If it cannot or if the value does not encode any bitfield,
- * the build will fail.
+ * Field specification must be a non-zero constant, otherwise the build
+ * will fail.
*
* If the value being stored in a bitfield is a constant that does not fit
* into that bitfield, a warning will be generated at compile time.
--
2.39.5
^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [PATCH 2/9] thunderblot: Don't pass a bitfield to FIELD_GET
2025-12-08 22:42 ` [PATCH 2/9] thunderblot: Don't pass a bitfield to FIELD_GET david.laight.linux
@ 2025-12-08 22:56 ` Greg KH
2025-12-09 10:36 ` David Laight
0 siblings, 1 reply; 23+ messages in thread
From: Greg KH @ 2025-12-08 22:56 UTC (permalink / raw)
To: david.laight.linux
Cc: Yury Norov, Rasmus Villemoes, linux-kernel, linux-usb,
Geert Uytterhoeven
On Mon, Dec 08, 2025 at 10:42:43PM +0000, david.laight.linux@gmail.com wrote:
> From: David Laight <david.laight.linux@gmail.com>
>
> FIELD_GET needs to use __auto_type to get the value of the 'reg'
> parameter, this can't be used with bifields.
>
> FIELD_GET also want to verify the size of 'reg' so can't add zero
> to force the type to int.
>
> So add a zero here.
>
> Signed-off-by: David Laight <david.laight.linux@gmail.com>
> ---
> drivers/thunderbolt/tb.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
> index e96474f17067..7ca2b5a0f01e 100644
> --- a/drivers/thunderbolt/tb.h
> +++ b/drivers/thunderbolt/tb.h
> @@ -1307,7 +1307,7 @@ static inline struct tb_retimer *tb_to_retimer(struct device *dev)
> */
> static inline unsigned int usb4_switch_version(const struct tb_switch *sw)
> {
> - return FIELD_GET(USB4_VERSION_MAJOR_MASK, sw->config.thunderbolt_version);
> + return FIELD_GET(USB4_VERSION_MAJOR_MASK, sw->config.thunderbolt_version + 0);
This is going to be very confusing to people who see this line only.
Can we add a comment here to explain why we have to do a "+ 0" and why
it can't be removed? Otherwise I'm going to get a bunch of "cleanup"
patches attempting to "fix" this over the next few years.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 3/9] bitmap: Use FIELD_PREP() in expansion of FIELD_PREP_WM16()
2025-12-08 22:42 ` [PATCH 3/9] bitmap: Use FIELD_PREP() in expansion of FIELD_PREP_WM16() david.laight.linux
@ 2025-12-09 0:54 ` Yury Norov
2025-12-09 9:56 ` David Laight
2025-12-11 18:53 ` David Laight
0 siblings, 2 replies; 23+ messages in thread
From: Yury Norov @ 2025-12-09 0:54 UTC (permalink / raw)
To: david.laight.linux
Cc: Rasmus Villemoes, linux-kernel, linux-usb, Geert Uytterhoeven,
Nicolas Frattaroli
+ Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
It's always good to CC an author of the original implementation,
isn't?
On Mon, Dec 08, 2025 at 10:42:44PM +0000, david.laight.linux@gmail.com wrote:
> From: David Laight <david.laight.linux@gmail.com>
>
> Instead of directly expanding __BF_FIELD_CHECK() (which really ought
> not be used outside bitfield) and open-coding the generation of the
> masked value, just call FIELD_PREP()
That's fair.
> and add an extra check for
> the mask being at most 16 bits.
Maybe it's time to introduce FIELD_PREP16()?
> Signed-off-by: David Laight <david.laight.linux@gmail.com>
> ---
> include/linux/hw_bitfield.h | 17 ++++++++---------
> 1 file changed, 8 insertions(+), 9 deletions(-)
>
> diff --git a/include/linux/hw_bitfield.h b/include/linux/hw_bitfield.h
> index df202e167ce4..d7f21b60449b 100644
> --- a/include/linux/hw_bitfield.h
> +++ b/include/linux/hw_bitfield.h
> @@ -23,15 +23,14 @@
> * register, a bit in the lower half is only updated if the corresponding bit
> * in the upper half is high.
> */
> -#define FIELD_PREP_WM16(_mask, _val) \
> - ({ \
> - typeof(_val) __val = _val; \
> - typeof(_mask) __mask = _mask; \
> - __BF_FIELD_CHECK(__mask, ((u16)0U), __val, \
> - "HWORD_UPDATE: "); \
> - (((typeof(__mask))(__val) << __bf_shf(__mask)) & (__mask)) | \
> - ((__mask) << 16); \
> - })
> +#define FIELD_PREP_WM16(mask, val) \
> +({ \
> + __auto_type _mask = mask; \
Is __auto_type any better than typeof()?
> + u32 _val = FIELD_PREP(_mask, val); \
> + BUILD_BUG_ON_MSG(_mask > 0xffffu, \
> + "FIELD_PREP_WM16: mask too large"); \
Not necessary to split this line.
> + _val | (_mask << 16); \
> +})
Can you share bloat-o-meter and code generation examples?
For the next version please try to keep as much history
untouched as possible.
Thanks,
Yury
>
> /**
> * FIELD_PREP_WM16_CONST() - prepare a constant bitfield element with a mask in
> --
> 2.39.5
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 0/9] bitfield: tidy up bitfield.h
2025-12-08 22:42 [PATCH 0/9] bitfield: tidy up bitfield.h david.laight.linux
` (8 preceding siblings ...)
2025-12-08 22:42 ` [PATCH 9/9] bitfield: Update comments for le/be functions david.laight.linux
@ 2025-12-09 7:08 ` Mika Westerberg
2025-12-09 7:49 ` Jakub Kicinski
2025-12-09 9:44 ` David Laight
9 siblings, 2 replies; 23+ messages in thread
From: Mika Westerberg @ 2025-12-09 7:08 UTC (permalink / raw)
To: david.laight.linux
Cc: Yury Norov, Rasmus Villemoes, linux-kernel, linux-usb,
Geert Uytterhoeven, Alexandre Belloni, Jonathan Cameron, Crt Mori,
Richard Genoud, Andy Shevchenko, Luo Jie, Peter Zijlstra,
Jakub Kicinski, netdev, David S . Miller, Simon Horman,
Andreas Noever, Yehezkel Bernat
Hi David,
On Mon, Dec 08, 2025 at 10:42:41PM +0000, david.laight.linux@gmail.com wrote:
> From: David Laight <david.laight.linux@gmail.com>
>
> I noticed some very long (18KB) error messages from the compiler.
> Turned out they were errors on lines that passed GENMASK() to FIELD_PREP().
> Since most of the #defines are already statement functions the values
> can be copied to locals so the actual parameters only get expanded once.
>
> The 'bloat' is reduced further by using a simple test to ensure 'reg'
> is large enough, slightly simplifying the test for constant 'val' and
> only checking 'reg' and 'val' when the parameters are present.
>
> The first two patches are slightly problematic.
>
> drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c manages to use
> a #define that should be an internal to bitfield.h, the changed file
> is actually more similar to the previous version.
>
> drivers/thunderbolt/tb.h passes a bifield to FIELD_GET(), these can't
> be used with sizeof or __auto_type. The usual solution is to add zero,
> but that can't be done in FIELD_GET() because it doesn't want the value
> promoted to 'int' (no idea how _Generic() treated it.)
> The fix is just to add zero at the call site.
> (The bitfield seems to be in a structure rad from hardware - no idea
> how that works on BE (or any LE that uses an unusual order for bitfields.)
Okay but can you CC me the actual patch too? I only got the cover letter
;-)
> Both changes may need to to through the same tree as the header file changes.
>
> The changes are based on 'next' and contain the addition of field_prep()
> and field_get() for non-constant values.
>
> I also know it is the merge window.
> I expect to be generating a v2 in the new year (someone always has a comment).
>
> David Laight (9):
> nfp: Call FIELD_PREP() in NFP_ETH_SET_BIT_CONFIG() wrapper
> thunderblot: Don't pass a bitfield to FIELD_GET
> bitmap: Use FIELD_PREP() in expansion of FIELD_PREP_WM16()
> bitfield: Copy #define parameters to locals
> bitfield: FIELD_MODIFY: Only do a single read/write on the target
> bitfield: Update sanity checks
> bitfield: Reduce indentation
> bitfield: Add comment block for the host/fixed endian functions
> bitfield: Update comments for le/be functions
>
> .../netronome/nfp/nfpcore/nfp_nsp_eth.c | 16 +-
> drivers/thunderbolt/tb.h | 2 +-
> include/linux/bitfield.h | 278 ++++++++++--------
> include/linux/hw_bitfield.h | 17 +-
> 4 files changed, 166 insertions(+), 147 deletions(-)
>
> --
> 2.39.5
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 0/9] bitfield: tidy up bitfield.h
2025-12-09 7:08 ` [PATCH 0/9] bitfield: tidy up bitfield.h Mika Westerberg
@ 2025-12-09 7:49 ` Jakub Kicinski
2025-12-09 9:44 ` David Laight
1 sibling, 0 replies; 23+ messages in thread
From: Jakub Kicinski @ 2025-12-09 7:49 UTC (permalink / raw)
To: Mika Westerberg, david.laight.linux
Cc: Yury Norov, Rasmus Villemoes, linux-kernel, linux-usb,
Geert Uytterhoeven, Alexandre Belloni, Jonathan Cameron, Crt Mori,
Richard Genoud, Andy Shevchenko, Luo Jie, Peter Zijlstra, netdev,
David S . Miller, Simon Horman, Andreas Noever, Yehezkel Bernat
On Tue, 9 Dec 2025 08:08:06 +0100 Mika Westerberg wrote:
> > drivers/thunderbolt/tb.h passes a bifield to FIELD_GET(), these can't
> > be used with sizeof or __auto_type. The usual solution is to add zero,
> > but that can't be done in FIELD_GET() because it doesn't want the value
> > promoted to 'int' (no idea how _Generic() treated it.)
> > The fix is just to add zero at the call site.
> > (The bitfield seems to be in a structure rad from hardware - no idea
> > how that works on BE (or any LE that uses an unusual order for bitfields.)
>
> Okay but can you CC me the actual patch too? I only got the cover letter
> ;-)
Right, David, please fix your CC lists. kernel dev 101..
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 0/9] bitfield: tidy up bitfield.h
2025-12-09 7:08 ` [PATCH 0/9] bitfield: tidy up bitfield.h Mika Westerberg
2025-12-09 7:49 ` Jakub Kicinski
@ 2025-12-09 9:44 ` David Laight
1 sibling, 0 replies; 23+ messages in thread
From: David Laight @ 2025-12-09 9:44 UTC (permalink / raw)
To: Mika Westerberg
Cc: Yury Norov, Rasmus Villemoes, linux-kernel, linux-usb,
Geert Uytterhoeven, Alexandre Belloni, Jonathan Cameron, Crt Mori,
Richard Genoud, Andy Shevchenko, Luo Jie, Peter Zijlstra,
Jakub Kicinski, netdev, David S . Miller, Simon Horman,
Andreas Noever, Yehezkel Bernat
On Tue, 9 Dec 2025 08:08:06 +0100
Mika Westerberg <mika.westerberg@linux.intel.com> wrote:
> Hi David,
>
> On Mon, Dec 08, 2025 at 10:42:41PM +0000, david.laight.linux@gmail.com wrote:
> > From: David Laight <david.laight.linux@gmail.com>
> >
> > I noticed some very long (18KB) error messages from the compiler.
> > Turned out they were errors on lines that passed GENMASK() to FIELD_PREP().
> > Since most of the #defines are already statement functions the values
> > can be copied to locals so the actual parameters only get expanded once.
> >
> > The 'bloat' is reduced further by using a simple test to ensure 'reg'
> > is large enough, slightly simplifying the test for constant 'val' and
> > only checking 'reg' and 'val' when the parameters are present.
> >
> > The first two patches are slightly problematic.
> >
> > drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c manages to use
> > a #define that should be an internal to bitfield.h, the changed file
> > is actually more similar to the previous version.
> >
> > drivers/thunderbolt/tb.h passes a bifield to FIELD_GET(), these can't
> > be used with sizeof or __auto_type. The usual solution is to add zero,
> > but that can't be done in FIELD_GET() because it doesn't want the value
> > promoted to 'int' (no idea how _Generic() treated it.)
> > The fix is just to add zero at the call site.
> > (The bitfield seems to be in a structure rad from hardware - no idea
> > how that works on BE (or any LE that uses an unusual order for bitfields.)
>
> Okay but can you CC me the actual patch too? I only got the cover letter
> ;-)
Ah, sorry I'd changed the git settings..
I'll resend it all.
David
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 3/9] bitmap: Use FIELD_PREP() in expansion of FIELD_PREP_WM16()
2025-12-09 0:54 ` Yury Norov
@ 2025-12-09 9:56 ` David Laight
2025-12-11 18:53 ` David Laight
1 sibling, 0 replies; 23+ messages in thread
From: David Laight @ 2025-12-09 9:56 UTC (permalink / raw)
To: Yury Norov
Cc: Rasmus Villemoes, linux-kernel, linux-usb, Geert Uytterhoeven,
Nicolas Frattaroli
On Mon, 8 Dec 2025 19:54:37 -0500
Yury Norov <yury.norov@gmail.com> wrote:
> + Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
>
> It's always good to CC an author of the original implementation,
> isn't?
>
> On Mon, Dec 08, 2025 at 10:42:44PM +0000, david.laight.linux@gmail.com wrote:
> > From: David Laight <david.laight.linux@gmail.com>
> >
> > Instead of directly expanding __BF_FIELD_CHECK() (which really ought
> > not be used outside bitfield) and open-coding the generation of the
> > masked value, just call FIELD_PREP()
>
> That's fair.
>
> > and add an extra check for
> > the mask being at most 16 bits.
>
> Maybe it's time to introduce FIELD_PREP16()?
>
> > Signed-off-by: David Laight <david.laight.linux@gmail.com>
> > ---
> > include/linux/hw_bitfield.h | 17 ++++++++---------
> > 1 file changed, 8 insertions(+), 9 deletions(-)
> >
> > diff --git a/include/linux/hw_bitfield.h b/include/linux/hw_bitfield.h
> > index df202e167ce4..d7f21b60449b 100644
> > --- a/include/linux/hw_bitfield.h
> > +++ b/include/linux/hw_bitfield.h
> > @@ -23,15 +23,14 @@
> > * register, a bit in the lower half is only updated if the corresponding bit
> > * in the upper half is high.
> > */
> > -#define FIELD_PREP_WM16(_mask, _val) \
> > - ({ \
> > - typeof(_val) __val = _val; \
> > - typeof(_mask) __mask = _mask; \
> > - __BF_FIELD_CHECK(__mask, ((u16)0U), __val, \
> > - "HWORD_UPDATE: "); \
> > - (((typeof(__mask))(__val) << __bf_shf(__mask)) & (__mask)) | \
> > - ((__mask) << 16); \
> > - })
> > +#define FIELD_PREP_WM16(mask, val) \
> > +({ \
> > + __auto_type _mask = mask; \
>
> Is __auto_type any better than typeof()?
Generally yes.
Mainly because you only get one expansion of the #define parameter.
>
> > + u32 _val = FIELD_PREP(_mask, val); \
> > + BUILD_BUG_ON_MSG(_mask > 0xffffu, \
> > + "FIELD_PREP_WM16: mask too large"); \
>
> Not necessary to split this line.
>
> > + _val | (_mask << 16); \
> > +})
>
> Can you share bloat-o-meter and code generation examples?
The generated code is going to be pretty much unchanged.
The changes only really affect the compile-time checks.
>
> For the next version please try to keep as much history
> untouched as possible.
I'm going to resend the same patches with the full cc list for now.
David
>
> Thanks,
> Yury
>
> >
> > /**
> > * FIELD_PREP_WM16_CONST() - prepare a constant bitfield element with a mask in
> > --
> > 2.39.5
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 4/9] bitfield: Copy #define parameters to locals
2025-12-09 10:03 david.laight.linux
@ 2025-12-09 10:03 ` david.laight.linux
2025-12-09 15:51 ` Andy Shevchenko
0 siblings, 1 reply; 23+ messages in thread
From: david.laight.linux @ 2025-12-09 10:03 UTC (permalink / raw)
To: Yury Norov, Rasmus Villemoes, linux-kernel, linux-usb,
Geert Uytterhoeven, Alexandre Belloni, Jonathan Cameron, Crt Mori,
Richard Genoud, Andy Shevchenko, Luo Jie, Peter Zijlstra,
Jakub Kicinski, netdev, David S . Miller, Simon Horman,
Mika Westerberg, Andreas Noever, Yehezkel Bernat,
Nicolas Frattaroli
Cc: David Laight
From: David Laight <david.laight.linux@gmail.com>
Use __auto_type to take copies of parameters to both ensure they are
evaluated only once and to avoid bloating the pre-processor output.
In particular 'mask' is likely to be GENMASK() and the expension
of FIELD_GET() is then about 18KB.
Remove any extra (), update kerneldoc.
Consistently use xxx for #define formal parameters and _xxx for
local variables.
Rather than use (typeof(mask))(val) to ensure bits aren't lost when
val is shifted left, use '__auto_type _val = 1 ? (val) : _mask;'
relying on the ?: operator to generate a type that is large enough.
Remove the (typeof(mask)) cast from __FIELD_GET(), it can only make
a difference if 'reg' is larger than 'mask' and the caller cares about
the actual type.
Note that mask usually comes from GENMASK() and is then 'unsigned long'.
Rename the internal defines __FIELD_PREP to __BF_FIELD_PREP and
__FIELD_GET to __BF_FIELD_GET.
Now that field_prep() and field_get() copy their parameters there is
no need for the __field_prep() and __field_get() defines.
But add a define to generate the required 'shift' to use in both defines.
Signed-off-by: David Laight <david.laight.linux@gmail.com>
---
include/linux/bitfield.h | 150 ++++++++++++++++++++-------------------
1 file changed, 78 insertions(+), 72 deletions(-)
diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
index 126dc5b380af..3e013da9ea12 100644
--- a/include/linux/bitfield.h
+++ b/include/linux/bitfield.h
@@ -61,17 +61,17 @@
#define __bf_cast_unsigned(type, x) ((__unsigned_scalar_typeof(type))(x))
-#define __BF_FIELD_CHECK_MASK(_mask, _val, _pfx) \
+#define __BF_FIELD_CHECK_MASK(mask, val, pfx) \
({ \
- BUILD_BUG_ON_MSG(!__builtin_constant_p(_mask), \
- _pfx "mask is not constant"); \
- BUILD_BUG_ON_MSG((_mask) == 0, _pfx "mask is zero"); \
- BUILD_BUG_ON_MSG(__builtin_constant_p(_val) ? \
- ~((_mask) >> __bf_shf(_mask)) & \
- (0 + (_val)) : 0, \
- _pfx "value too large for the field"); \
- __BUILD_BUG_ON_NOT_POWER_OF_2((_mask) + \
- (1ULL << __bf_shf(_mask))); \
+ BUILD_BUG_ON_MSG(!__builtin_constant_p(mask), \
+ pfx "mask is not constant"); \
+ BUILD_BUG_ON_MSG((mask) == 0, _pfx "mask is zero"); \
+ BUILD_BUG_ON_MSG(__builtin_constant_p(val) ? \
+ ~((mask) >> __bf_shf(mask)) & \
+ (0 + (val)) : 0, \
+ pfx "value too large for the field"); \
+ __BUILD_BUG_ON_NOT_POWER_OF_2((mask) + \
+ (1ULL << __bf_shf(mask))); \
})
#define __BF_FIELD_CHECK_REG(mask, reg, pfx) \
@@ -85,64 +85,69 @@
__BF_FIELD_CHECK_REG(mask, reg, pfx); \
})
-#define __FIELD_PREP(mask, val, pfx) \
+#define __BF_FIELD_PREP(mask, val, pfx) \
({ \
__BF_FIELD_CHECK_MASK(mask, val, pfx); \
- ((typeof(mask))(val) << __bf_shf(mask)) & (mask); \
+ ((val) << __bf_shf(mask)) & (mask); \
})
-#define __FIELD_GET(mask, reg, pfx) \
+#define __BF_FIELD_GET(mask, reg, pfx) \
({ \
__BF_FIELD_CHECK_MASK(mask, 0U, pfx); \
- (typeof(mask))(((reg) & (mask)) >> __bf_shf(mask)); \
+ ((reg) & (mask)) >> __bf_shf(mask); \
})
/**
* FIELD_MAX() - produce the maximum value representable by a field
- * @_mask: shifted mask defining the field's length and position
+ * @mask: shifted mask defining the field's length and position
*
* FIELD_MAX() returns the maximum value that can be held in the field
- * specified by @_mask.
+ * specified by @mask.
*/
-#define FIELD_MAX(_mask) \
+#define FIELD_MAX(mask) \
({ \
+ __auto_type _mask = mask; \
__BF_FIELD_CHECK(_mask, 0ULL, 0ULL, "FIELD_MAX: "); \
- (typeof(_mask))((_mask) >> __bf_shf(_mask)); \
+ (_mask >> __bf_shf(_mask)); \
})
/**
* FIELD_FIT() - check if value fits in the field
- * @_mask: shifted mask defining the field's length and position
- * @_val: value to test against the field
+ * @mask: shifted mask defining the field's length and position
+ * @val: value to test against the field
*
- * Return: true if @_val can fit inside @_mask, false if @_val is too big.
+ * Return: true if @val can fit inside @mask, false if @val is too big.
*/
-#define FIELD_FIT(_mask, _val) \
+#define FIELD_FIT(mask, val) \
({ \
+ __auto_type _mask = mask; \
+ __auto_type _val = 1 ? (val) : _mask; \
__BF_FIELD_CHECK(_mask, 0ULL, 0ULL, "FIELD_FIT: "); \
- !((((typeof(_mask))_val) << __bf_shf(_mask)) & ~(_mask)); \
+ !((_val << __bf_shf(_mask)) & ~_mask); \
})
/**
* FIELD_PREP() - prepare a bitfield element
- * @_mask: shifted mask defining the field's length and position
- * @_val: value to put in the field
+ * @mask: shifted mask defining the field's length and position
+ * @val: value to put in the field
*
* FIELD_PREP() masks and shifts up the value. The result should
* be combined with other fields of the bitfield using logical OR.
*/
-#define FIELD_PREP(_mask, _val) \
+#define FIELD_PREP(mask, val) \
({ \
+ __auto_type _mask = mask; \
+ __auto_type _val = 1 ? (val) : _mask; \
__BF_FIELD_CHECK_REG(_mask, 0ULL, "FIELD_PREP: "); \
- __FIELD_PREP(_mask, _val, "FIELD_PREP: "); \
+ __BF_FIELD_PREP(_mask, _val, "FIELD_PREP: "); \
})
#define __BF_CHECK_POW2(n) BUILD_BUG_ON_ZERO(((n) & ((n) - 1)) != 0)
/**
* FIELD_PREP_CONST() - prepare a constant bitfield element
- * @_mask: shifted mask defining the field's length and position
- * @_val: value to put in the field
+ * @mask: shifted mask defining the field's length and position
+ * @val: value to put in the field
*
* FIELD_PREP_CONST() masks and shifts up the value. The result should
* be combined with other fields of the bitfield using logical OR.
@@ -151,47 +156,52 @@
* be used in initializers. Error checking is less comfortable for this
* version, and non-constant masks cannot be used.
*/
-#define FIELD_PREP_CONST(_mask, _val) \
+#define FIELD_PREP_CONST(mask, val) \
( \
/* mask must be non-zero */ \
- BUILD_BUG_ON_ZERO((_mask) == 0) + \
+ BUILD_BUG_ON_ZERO((mask) == 0) + \
/* check if value fits */ \
- BUILD_BUG_ON_ZERO(~((_mask) >> __bf_shf(_mask)) & (_val)) + \
+ BUILD_BUG_ON_ZERO(~((mask) >> __bf_shf(mask)) & (val)) + \
/* check if mask is contiguous */ \
- __BF_CHECK_POW2((_mask) + (1ULL << __bf_shf(_mask))) + \
+ __BF_CHECK_POW2((mask) + (1ULL << __bf_shf(mask))) + \
/* and create the value */ \
- (((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask)) \
+ (((typeof(mask))(val) << __bf_shf(mask)) & (mask)) \
)
/**
* FIELD_GET() - extract a bitfield element
- * @_mask: shifted mask defining the field's length and position
- * @_reg: value of entire bitfield
+ * @mask: shifted mask defining the field's length and position
+ * @reg: value of entire bitfield
*
- * FIELD_GET() extracts the field specified by @_mask from the
- * bitfield passed in as @_reg by masking and shifting it down.
+ * FIELD_GET() extracts the field specified by @mask from the
+ * bitfield passed in as @reg by masking and shifting it down.
*/
-#define FIELD_GET(_mask, _reg) \
+#define FIELD_GET(mask, reg) \
({ \
+ __auto_type _mask = mask; \
+ __auto_type _reg = reg; \
__BF_FIELD_CHECK_REG(_mask, _reg, "FIELD_GET: "); \
- __FIELD_GET(_mask, _reg, "FIELD_GET: "); \
+ __BF_FIELD_GET(_mask, _reg, "FIELD_GET: "); \
})
/**
* FIELD_MODIFY() - modify a bitfield element
- * @_mask: shifted mask defining the field's length and position
- * @_reg_p: pointer to the memory that should be updated
- * @_val: value to store in the bitfield
+ * @mask: shifted mask defining the field's length and position
+ * @reg_p: pointer to the memory that should be updated
+ * @val: value to store in the bitfield
*
- * FIELD_MODIFY() modifies the set of bits in @_reg_p specified by @_mask,
- * by replacing them with the bitfield value passed in as @_val.
+ * FIELD_MODIFY() modifies the set of bits in @reg_p specified by @mask,
+ * by replacing them with the bitfield value passed in as @val.
*/
-#define FIELD_MODIFY(_mask, _reg_p, _val) \
+#define FIELD_MODIFY(mask, reg_p, val) \
({ \
+ __auto_type _mask = mask; \
+ __auto_type _reg_p = reg_p; \
+ __auto_type _val = 1 ? (val) : _mask; \
typecheck_pointer(_reg_p); \
- __BF_FIELD_CHECK(_mask, *(_reg_p), _val, "FIELD_MODIFY: "); \
- *(_reg_p) &= ~(_mask); \
- *(_reg_p) |= (((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask)); \
+ __BF_FIELD_CHECK(_mask, *_reg_p, _val, "FIELD_MODIFY: "); \
+ *_reg_p &= ~_mask; \
+ *_reg_p |= ((_val << __bf_shf(_mask)) & _mask); \
})
extern void __compiletime_error("value doesn't fit into mask")
@@ -241,23 +251,9 @@ __MAKE_OP(64)
#undef __MAKE_OP
#undef ____MAKE_OP
-#define __field_prep(mask, val) \
- ({ \
- __auto_type __mask = (mask); \
- typeof(__mask) __val = (val); \
- unsigned int __shift = BITS_PER_TYPE(__mask) <= 32 ? \
- __ffs(__mask) : __ffs64(__mask); \
- (__val << __shift) & __mask; \
- })
-
-#define __field_get(mask, reg) \
- ({ \
- __auto_type __mask = (mask); \
- typeof(__mask) __reg = (reg); \
- unsigned int __shift = BITS_PER_TYPE(__mask) <= 32 ? \
- __ffs(__mask) : __ffs64(__mask); \
- (__reg & __mask) >> __shift; \
- })
+/* As __bf_shf() but for non-zero variables */
+#define __BF_SHIFT(mask) \
+ (BITS_PER_TYPE(_mask) <= 32 ? __ffs(_mask) : __ffs64(_mask))
/**
* field_prep() - prepare a bitfield element
@@ -275,9 +271,14 @@ __MAKE_OP(64)
* If you want to ensure that @mask is a compile-time constant, please use
* FIELD_PREP() directly instead.
*/
-#define field_prep(mask, val) \
- (__builtin_constant_p(mask) ? __FIELD_PREP(mask, val, "field_prep: ") \
- : __field_prep(mask, val))
+#define field_prep(mask, val) \
+({ \
+ __auto_type _mask = mask; \
+ __auto_type _val = 1 ? (val) : _mask; \
+ __builtin_constant_p(_mask) ? \
+ __BF_FIELD_PREP(_mask, _val, "field_prep: ") : \
+ (_val << __BF_SHIFT(_mask)) & _mask; \
+})
/**
* field_get() - extract a bitfield element
@@ -295,8 +296,13 @@ __MAKE_OP(64)
* If you want to ensure that @mask is a compile-time constant, please use
* FIELD_GET() directly instead.
*/
-#define field_get(mask, reg) \
- (__builtin_constant_p(mask) ? __FIELD_GET(mask, reg, "field_get: ") \
- : __field_get(mask, reg))
+#define field_get(mask, reg) \
+({ \
+ __auto_type _mask = mask; \
+ __auto_type _reg = reg; \
+ __builtin_constant_p(_mask) ? \
+ __BF_FIELD_GET(_mask, _reg, "field_get: ") : \
+ (_reg & _mask) >> __BF_SHIFT(_mask); \
+})
#endif
--
2.39.5
^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [PATCH 2/9] thunderblot: Don't pass a bitfield to FIELD_GET
2025-12-08 22:56 ` Greg KH
@ 2025-12-09 10:36 ` David Laight
0 siblings, 0 replies; 23+ messages in thread
From: David Laight @ 2025-12-09 10:36 UTC (permalink / raw)
To: Greg KH
Cc: Yury Norov, Rasmus Villemoes, linux-kernel, linux-usb,
Geert Uytterhoeven
On Tue, 9 Dec 2025 07:56:35 +0900
Greg KH <gregkh@linuxfoundation.org> wrote:
> On Mon, Dec 08, 2025 at 10:42:43PM +0000, david.laight.linux@gmail.com wrote:
> > From: David Laight <david.laight.linux@gmail.com>
> >
> > FIELD_GET needs to use __auto_type to get the value of the 'reg'
> > parameter, this can't be used with bifields.
> >
> > FIELD_GET also want to verify the size of 'reg' so can't add zero
> > to force the type to int.
> >
> > So add a zero here.
> >
> > Signed-off-by: David Laight <david.laight.linux@gmail.com>
> > ---
> > drivers/thunderbolt/tb.h | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
> > index e96474f17067..7ca2b5a0f01e 100644
> > --- a/drivers/thunderbolt/tb.h
> > +++ b/drivers/thunderbolt/tb.h
> > @@ -1307,7 +1307,7 @@ static inline struct tb_retimer *tb_to_retimer(struct device *dev)
> > */
> > static inline unsigned int usb4_switch_version(const struct tb_switch *sw)
> > {
> > - return FIELD_GET(USB4_VERSION_MAJOR_MASK, sw->config.thunderbolt_version);
> > + return FIELD_GET(USB4_VERSION_MAJOR_MASK, sw->config.thunderbolt_version + 0);
>
> This is going to be very confusing to people who see this line only.
> Can we add a comment here to explain why we have to do a "+ 0" and why
> it can't be removed? Otherwise I'm going to get a bunch of "cleanup"
> patches attempting to "fix" this over the next few years.
I've added a comment for v2 (but not the resend I did for the cc 'issue').
I've also fixed the subject blot => bolt.
I also noticed that the 'int thunderbolt_version:8' seems to be in a structure
that maps something read from the hardware.
That isn't going to be right on any BE system, and isn't guaranteed on LE ones.
David
>
> thanks,
>
> greg k-h
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 4/9] bitfield: Copy #define parameters to locals
2025-12-09 10:03 ` [PATCH 4/9] bitfield: Copy #define parameters to locals david.laight.linux
@ 2025-12-09 15:51 ` Andy Shevchenko
2025-12-09 19:11 ` David Laight
2025-12-10 18:45 ` Yury Norov
0 siblings, 2 replies; 23+ messages in thread
From: Andy Shevchenko @ 2025-12-09 15:51 UTC (permalink / raw)
To: david.laight.linux
Cc: Yury Norov, Rasmus Villemoes, linux-kernel, linux-usb,
Geert Uytterhoeven, Alexandre Belloni, Jonathan Cameron, Crt Mori,
Richard Genoud, Luo Jie, Peter Zijlstra, Jakub Kicinski, netdev,
David S . Miller, Simon Horman, Mika Westerberg, Andreas Noever,
Yehezkel Bernat, Nicolas Frattaroli
On Tue, Dec 09, 2025 at 10:03:08AM +0000, david.laight.linux@gmail.com wrote:
> Use __auto_type to take copies of parameters to both ensure they are
> evaluated only once and to avoid bloating the pre-processor output.
> In particular 'mask' is likely to be GENMASK() and the expension
> of FIELD_GET() is then about 18KB.
>
> Remove any extra (), update kerneldoc.
> Consistently use xxx for #define formal parameters and _xxx for
> local variables.
Okay, I commented below, and I think this is too huge to be in this commit.
Can we make it separate?
> Rather than use (typeof(mask))(val) to ensure bits aren't lost when
> val is shifted left, use '__auto_type _val = 1 ? (val) : _mask;'
> relying on the ?: operator to generate a type that is large enough.
>
> Remove the (typeof(mask)) cast from __FIELD_GET(), it can only make
> a difference if 'reg' is larger than 'mask' and the caller cares about
> the actual type.
> Note that mask usually comes from GENMASK() and is then 'unsigned long'.
>
> Rename the internal defines __FIELD_PREP to __BF_FIELD_PREP and
> __FIELD_GET to __BF_FIELD_GET.
>
> Now that field_prep() and field_get() copy their parameters there is
> no need for the __field_prep() and __field_get() defines.
> But add a define to generate the required 'shift' to use in both defines.
...
> -#define __BF_FIELD_CHECK_MASK(_mask, _val, _pfx) \
> +#define __BF_FIELD_CHECK_MASK(mask, val, pfx) \
> ({ \
> - BUILD_BUG_ON_MSG(!__builtin_constant_p(_mask), \
> - _pfx "mask is not constant"); \
> - BUILD_BUG_ON_MSG((_mask) == 0, _pfx "mask is zero"); \
> - BUILD_BUG_ON_MSG(__builtin_constant_p(_val) ? \
> - ~((_mask) >> __bf_shf(_mask)) & \
> - (0 + (_val)) : 0, \
> - _pfx "value too large for the field"); \
> - __BUILD_BUG_ON_NOT_POWER_OF_2((_mask) + \
> - (1ULL << __bf_shf(_mask))); \
> + BUILD_BUG_ON_MSG(!__builtin_constant_p(mask), \
> + pfx "mask is not constant"); \
> + BUILD_BUG_ON_MSG((mask) == 0, _pfx "mask is zero"); \
> + BUILD_BUG_ON_MSG(__builtin_constant_p(val) ? \
> + ~((mask) >> __bf_shf(mask)) & \
> + (0 + (val)) : 0, \
> + pfx "value too large for the field"); \
> + __BUILD_BUG_ON_NOT_POWER_OF_2((mask) + \
> + (1ULL << __bf_shf(mask))); \
> })
I looks like renaming parameters without any benefit, actually the opposite
it's very hard to see if there is any interesting change here. Please, drop
this or make it clear to focus only on the things that needs to be changed.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 4/9] bitfield: Copy #define parameters to locals
2025-12-09 15:51 ` Andy Shevchenko
@ 2025-12-09 19:11 ` David Laight
2025-12-09 21:54 ` Andy Shevchenko
2025-12-10 18:45 ` Yury Norov
1 sibling, 1 reply; 23+ messages in thread
From: David Laight @ 2025-12-09 19:11 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Yury Norov, Rasmus Villemoes, linux-kernel, linux-usb,
Geert Uytterhoeven, Alexandre Belloni, Jonathan Cameron, Crt Mori,
Richard Genoud, Luo Jie, Peter Zijlstra, Jakub Kicinski, netdev,
David S . Miller, Simon Horman, Mika Westerberg, Andreas Noever,
Yehezkel Bernat, Nicolas Frattaroli
On Tue, 9 Dec 2025 17:51:48 +0200
Andy Shevchenko <andriy.shevchenko@intel.com> wrote:
> On Tue, Dec 09, 2025 at 10:03:08AM +0000, david.laight.linux@gmail.com wrote:
>
> > Use __auto_type to take copies of parameters to both ensure they are
> > evaluated only once and to avoid bloating the pre-processor output.
> > In particular 'mask' is likely to be GENMASK() and the expension
> > of FIELD_GET() is then about 18KB.
> >
> > Remove any extra (), update kerneldoc.
>
> > Consistently use xxx for #define formal parameters and _xxx for
> > local variables.
>
> Okay, I commented below, and I think this is too huge to be in this commit.
> Can we make it separate?
I originally wrote a much longer patch set, then merged some to reduce
the number of patches - you can't win really.
>
> > Rather than use (typeof(mask))(val) to ensure bits aren't lost when
> > val is shifted left, use '__auto_type _val = 1 ? (val) : _mask;'
> > relying on the ?: operator to generate a type that is large enough.
> >
> > Remove the (typeof(mask)) cast from __FIELD_GET(), it can only make
> > a difference if 'reg' is larger than 'mask' and the caller cares about
> > the actual type.
> > Note that mask usually comes from GENMASK() and is then 'unsigned long'.
> >
> > Rename the internal defines __FIELD_PREP to __BF_FIELD_PREP and
> > __FIELD_GET to __BF_FIELD_GET.
> >
> > Now that field_prep() and field_get() copy their parameters there is
> > no need for the __field_prep() and __field_get() defines.
> > But add a define to generate the required 'shift' to use in both defines.
>
> ...
>
> > -#define __BF_FIELD_CHECK_MASK(_mask, _val, _pfx) \
> > +#define __BF_FIELD_CHECK_MASK(mask, val, pfx) \
> > ({ \
> > - BUILD_BUG_ON_MSG(!__builtin_constant_p(_mask), \
> > - _pfx "mask is not constant"); \
> > - BUILD_BUG_ON_MSG((_mask) == 0, _pfx "mask is zero"); \
> > - BUILD_BUG_ON_MSG(__builtin_constant_p(_val) ? \
> > - ~((_mask) >> __bf_shf(_mask)) & \
> > - (0 + (_val)) : 0, \
> > - _pfx "value too large for the field"); \
> > - __BUILD_BUG_ON_NOT_POWER_OF_2((_mask) + \
> > - (1ULL << __bf_shf(_mask))); \
> > + BUILD_BUG_ON_MSG(!__builtin_constant_p(mask), \
> > + pfx "mask is not constant"); \
> > + BUILD_BUG_ON_MSG((mask) == 0, _pfx "mask is zero"); \
> > + BUILD_BUG_ON_MSG(__builtin_constant_p(val) ? \
> > + ~((mask) >> __bf_shf(mask)) & \
> > + (0 + (val)) : 0, \
> > + pfx "value too large for the field"); \
> > + __BUILD_BUG_ON_NOT_POWER_OF_2((mask) + \
> > + (1ULL << __bf_shf(mask))); \
> > })
>
> I looks like renaming parameters without any benefit, actually the opposite
> it's very hard to see if there is any interesting change here. Please, drop
> this or make it clear to focus only on the things that needs to be changed.
I'm pretty sure there are no other changes in that bit.
(The entire define is pretty much re-written in a later patch and I
did want to separate the changes.)
I wanted to the file to be absolutely consistent with the parameter/variable
names.
Plausibly the scheme could be slightly different:
'user' parameters are 'xxx', '__auto_type' variables are '_xxx'.
But internal defines that evaluate/expand parameters more than once are
'_xxx' and must be 'copied' by an outer define.
David
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 4/9] bitfield: Copy #define parameters to locals
2025-12-09 19:11 ` David Laight
@ 2025-12-09 21:54 ` Andy Shevchenko
0 siblings, 0 replies; 23+ messages in thread
From: Andy Shevchenko @ 2025-12-09 21:54 UTC (permalink / raw)
To: David Laight
Cc: Yury Norov, Rasmus Villemoes, linux-kernel, linux-usb,
Geert Uytterhoeven, Alexandre Belloni, Jonathan Cameron, Crt Mori,
Richard Genoud, Luo Jie, Peter Zijlstra, Jakub Kicinski, netdev,
David S . Miller, Simon Horman, Mika Westerberg, Andreas Noever,
Yehezkel Bernat, Nicolas Frattaroli
On Tue, Dec 09, 2025 at 07:11:48PM +0000, David Laight wrote:
> On Tue, 9 Dec 2025 17:51:48 +0200
> Andy Shevchenko <andriy.shevchenko@intel.com> wrote:
> > On Tue, Dec 09, 2025 at 10:03:08AM +0000, david.laight.linux@gmail.com wrote:
...
> > > -#define __BF_FIELD_CHECK_MASK(_mask, _val, _pfx) \
> > > +#define __BF_FIELD_CHECK_MASK(mask, val, pfx) \
> > > ({ \
> > > - BUILD_BUG_ON_MSG(!__builtin_constant_p(_mask), \
> > > - _pfx "mask is not constant"); \
> > > - BUILD_BUG_ON_MSG((_mask) == 0, _pfx "mask is zero"); \
> > > - BUILD_BUG_ON_MSG(__builtin_constant_p(_val) ? \
> > > - ~((_mask) >> __bf_shf(_mask)) & \
> > > - (0 + (_val)) : 0, \
> > > - _pfx "value too large for the field"); \
> > > - __BUILD_BUG_ON_NOT_POWER_OF_2((_mask) + \
> > > - (1ULL << __bf_shf(_mask))); \
> > > + BUILD_BUG_ON_MSG(!__builtin_constant_p(mask), \
> > > + pfx "mask is not constant"); \
> > > + BUILD_BUG_ON_MSG((mask) == 0, _pfx "mask is zero"); \
> > > + BUILD_BUG_ON_MSG(__builtin_constant_p(val) ? \
> > > + ~((mask) >> __bf_shf(mask)) & \
> > > + (0 + (val)) : 0, \
> > > + pfx "value too large for the field"); \
> > > + __BUILD_BUG_ON_NOT_POWER_OF_2((mask) + \
> > > + (1ULL << __bf_shf(mask))); \
> > > })
> >
> > I looks like renaming parameters without any benefit, actually the opposite
> > it's very hard to see if there is any interesting change here. Please, drop
> > this or make it clear to focus only on the things that needs to be changed.
>
> I'm pretty sure there are no other changes in that bit.
Yes, but the rule of thumb to avoid putting several logical changes into a
single patch and here AFAICT the renaming should be avoided / split to a
precursor or do it after this.
> (The entire define is pretty much re-written in a later patch and I
> did want to separate the changes.)
Then probably don't do the change at all (renaming), as it's useless here?
> I wanted to the file to be absolutely consistent with the parameter/variable
> names.
No objection on this.
> Plausibly the scheme could be slightly different:
> 'user' parameters are 'xxx', '__auto_type' variables are '_xxx'.
> But internal defines that evaluate/expand parameters more than once are
> '_xxx' and must be 'copied' by an outer define.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 4/9] bitfield: Copy #define parameters to locals
2025-12-09 15:51 ` Andy Shevchenko
2025-12-09 19:11 ` David Laight
@ 2025-12-10 18:45 ` Yury Norov
1 sibling, 0 replies; 23+ messages in thread
From: Yury Norov @ 2025-12-10 18:45 UTC (permalink / raw)
To: Andy Shevchenko
Cc: david.laight.linux, Rasmus Villemoes, linux-kernel, linux-usb,
Geert Uytterhoeven, Alexandre Belloni, Jonathan Cameron, Crt Mori,
Richard Genoud, Luo Jie, Peter Zijlstra, Jakub Kicinski, netdev,
David S . Miller, Simon Horman, Mika Westerberg, Andreas Noever,
Yehezkel Bernat, Nicolas Frattaroli
On Tue, Dec 09, 2025 at 05:51:48PM +0200, Andy Shevchenko wrote:
> On Tue, Dec 09, 2025 at 10:03:08AM +0000, david.laight.linux@gmail.com wrote:
>
> > Use __auto_type to take copies of parameters to both ensure they are
> > evaluated only once and to avoid bloating the pre-processor output.
> > In particular 'mask' is likely to be GENMASK() and the expension
> > of FIELD_GET() is then about 18KB.
> >
> > Remove any extra (), update kerneldoc.
>
> > Consistently use xxx for #define formal parameters and _xxx for
> > local variables.
>
> Okay, I commented below, and I think this is too huge to be in this commit.
> Can we make it separate?
I'm next to Andy. The commit message covers 6 or 7 independent
changes, and patch body itself seems to be above my abilities to
review. This should look like a series if nice cleanups, now it looks
like a patch bomb.
> > Rather than use (typeof(mask))(val) to ensure bits aren't lost when
> > val is shifted left, use '__auto_type _val = 1 ? (val) : _mask;'
> > relying on the ?: operator to generate a type that is large enough.
> >
> > Remove the (typeof(mask)) cast from __FIELD_GET(), it can only make
> > a difference if 'reg' is larger than 'mask' and the caller cares about
> > the actual type.
> > Note that mask usually comes from GENMASK() and is then 'unsigned long'.
> >
> > Rename the internal defines __FIELD_PREP to __BF_FIELD_PREP and
> > __FIELD_GET to __BF_FIELD_GET.
> >
> > Now that field_prep() and field_get() copy their parameters there is
> > no need for the __field_prep() and __field_get() defines.
> > But add a define to generate the required 'shift' to use in both defines.
>
> ...
>
> > -#define __BF_FIELD_CHECK_MASK(_mask, _val, _pfx) \
> > +#define __BF_FIELD_CHECK_MASK(mask, val, pfx) \
> > ({ \
> > - BUILD_BUG_ON_MSG(!__builtin_constant_p(_mask), \
> > - _pfx "mask is not constant"); \
> > - BUILD_BUG_ON_MSG((_mask) == 0, _pfx "mask is zero"); \
> > - BUILD_BUG_ON_MSG(__builtin_constant_p(_val) ? \
> > - ~((_mask) >> __bf_shf(_mask)) & \
> > - (0 + (_val)) : 0, \
> > - _pfx "value too large for the field"); \
> > - __BUILD_BUG_ON_NOT_POWER_OF_2((_mask) + \
> > - (1ULL << __bf_shf(_mask))); \
> > + BUILD_BUG_ON_MSG(!__builtin_constant_p(mask), \
> > + pfx "mask is not constant"); \
> > + BUILD_BUG_ON_MSG((mask) == 0, _pfx "mask is zero"); \
> > + BUILD_BUG_ON_MSG(__builtin_constant_p(val) ? \
> > + ~((mask) >> __bf_shf(mask)) & \
> > + (0 + (val)) : 0, \
> > + pfx "value too large for the field"); \
> > + __BUILD_BUG_ON_NOT_POWER_OF_2((mask) + \
> > + (1ULL << __bf_shf(mask))); \
> > })
>
> I looks like renaming parameters without any benefit, actually the opposite
> it's very hard to see if there is any interesting change here. Please, drop
> this or make it clear to focus only on the things that needs to be changed.
>
> --
> With Best Regards,
> Andy Shevchenko
>
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 3/9] bitmap: Use FIELD_PREP() in expansion of FIELD_PREP_WM16()
2025-12-09 0:54 ` Yury Norov
2025-12-09 9:56 ` David Laight
@ 2025-12-11 18:53 ` David Laight
1 sibling, 0 replies; 23+ messages in thread
From: David Laight @ 2025-12-11 18:53 UTC (permalink / raw)
To: Yury Norov
Cc: Rasmus Villemoes, linux-kernel, linux-usb, Geert Uytterhoeven,
Nicolas Frattaroli
On Mon, 8 Dec 2025 19:54:37 -0500
Yury Norov <yury.norov@gmail.com> wrote:
> + Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
>
> It's always good to CC an author of the original implementation,
> isn't?
>
> On Mon, Dec 08, 2025 at 10:42:44PM +0000, david.laight.linux@gmail.com wrote:
> > From: David Laight <david.laight.linux@gmail.com>
> >
> > Instead of directly expanding __BF_FIELD_CHECK() (which really ought
> > not be used outside bitfield) and open-coding the generation of the
> > masked value, just call FIELD_PREP()
>
> That's fair.
>
> > and add an extra check for
> > the mask being at most 16 bits.
>
> Maybe it's time to introduce FIELD_PREP16()?
>
> > Signed-off-by: David Laight <david.laight.linux@gmail.com>
> > ---
> > include/linux/hw_bitfield.h | 17 ++++++++---------
> > 1 file changed, 8 insertions(+), 9 deletions(-)
> >
> > diff --git a/include/linux/hw_bitfield.h b/include/linux/hw_bitfield.h
> > index df202e167ce4..d7f21b60449b 100644
> > --- a/include/linux/hw_bitfield.h
> > +++ b/include/linux/hw_bitfield.h
> > @@ -23,15 +23,14 @@
> > * register, a bit in the lower half is only updated if the corresponding bit
> > * in the upper half is high.
> > */
> > -#define FIELD_PREP_WM16(_mask, _val) \
> > - ({ \
> > - typeof(_val) __val = _val; \
> > - typeof(_mask) __mask = _mask; \
> > - __BF_FIELD_CHECK(__mask, ((u16)0U), __val, \
> > - "HWORD_UPDATE: "); \
> > - (((typeof(__mask))(__val) << __bf_shf(__mask)) & (__mask)) | \
> > - ((__mask) << 16); \
> > - })
> > +#define FIELD_PREP_WM16(mask, val) \
> > +({ \
> > + __auto_type _mask = mask; \
>
> Is __auto_type any better than typeof()?
There is likely to be pressure for a global change soon.
6.19 contains '#define auto __auto_type' to match C23.
>
> > + u32 _val = FIELD_PREP(_mask, val); \
> > + BUILD_BUG_ON_MSG(_mask > 0xffffu, \
> > + "FIELD_PREP_WM16: mask too large"); \
>
> Not necessary to split this line.
Only because I removed a level on indentation.
>
> > + _val | (_mask << 16); \
> > +})
>
> Can you share bloat-o-meter and code generation examples?
>
> For the next version please try to keep as much history
> untouched as possible.
Even the minimal changes (not moving the continuation markers) change pretty
much all the lines.
So It really isn't worth trying to keep it.
David
^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2025-12-11 18:53 UTC | newest]
Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-08 22:42 [PATCH 0/9] bitfield: tidy up bitfield.h david.laight.linux
2025-12-08 22:42 ` [PATCH 1/9] nfp: Call FIELD_PREP() in NFP_ETH_SET_BIT_CONFIG() wrapper david.laight.linux
2025-12-08 22:42 ` [PATCH 2/9] thunderblot: Don't pass a bitfield to FIELD_GET david.laight.linux
2025-12-08 22:56 ` Greg KH
2025-12-09 10:36 ` David Laight
2025-12-08 22:42 ` [PATCH 3/9] bitmap: Use FIELD_PREP() in expansion of FIELD_PREP_WM16() david.laight.linux
2025-12-09 0:54 ` Yury Norov
2025-12-09 9:56 ` David Laight
2025-12-11 18:53 ` David Laight
2025-12-08 22:42 ` [PATCH 4/9] bitfield: Copy #define parameters to locals david.laight.linux
2025-12-08 22:42 ` [PATCH 5/9] bitfield: FIELD_MODIFY: Only do a single read/write on the target david.laight.linux
2025-12-08 22:42 ` [PATCH 6/9] bitfield: Update sanity checks david.laight.linux
2025-12-08 22:42 ` [PATCH 7/9] bitfield: Reduce indentation david.laight.linux
2025-12-08 22:42 ` [PATCH 8/9] bitfield: Add comment block for the host/fixed endian functions david.laight.linux
2025-12-08 22:42 ` [PATCH 9/9] bitfield: Update comments for le/be functions david.laight.linux
2025-12-09 7:08 ` [PATCH 0/9] bitfield: tidy up bitfield.h Mika Westerberg
2025-12-09 7:49 ` Jakub Kicinski
2025-12-09 9:44 ` David Laight
-- strict thread matches above, loose matches on Subject: below --
2025-12-09 10:03 david.laight.linux
2025-12-09 10:03 ` [PATCH 4/9] bitfield: Copy #define parameters to locals david.laight.linux
2025-12-09 15:51 ` Andy Shevchenko
2025-12-09 19:11 ` David Laight
2025-12-09 21:54 ` Andy Shevchenko
2025-12-10 18:45 ` Yury Norov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).