summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorGeert Uytterhoeven <[email protected]>2026-07-03 14:56:12 +0300
committerTom Rini <[email protected]>2026-07-08 13:29:18 -0600
commitda10fca9b062bde09144d65a0559676c658ac0ae (patch)
tree9a43f9b47ae15c0f75b623c079fc1bab92d44420 /include
parent9c10cba536874641bbc70a53588d6a59c9292e2e (diff)
bitfield: Add non-constant field_{prep, get}() helpers
The existing FIELD_{GET,PREP}() macros are limited to compile-time constants. However, it is very common to prepare or extract bitfield elements where the bitfield mask is not a compile-time constant. To avoid this limitation, the AT91 clock driver and several other drivers already have their own non-const field_{prep,get}() macros. Make them available for general use by adding them to <linux/bitfield.h>, and improve them slightly: 1. Avoid evaluating macro parameters more than once, 2. Replace "ffs() - 1" by "__ffs()", 3. Support 64-bit use on 32-bit architectures, 4. Wire field_{get,prep}() to FIELD_{GET,PREP}() when mask is actually constant. This is deliberately not merged into the existing FIELD_{GET,PREP}() macros, as people expressed the desire to keep stricter variants for increased safety, or for performance critical paths. Yury: use __mask within new macros. Signed-off-by: Geert Uytterhoeven <[email protected]> Acked-by: Alexandre Belloni <[email protected]> Acked-by: Jonathan Cameron <[email protected]> Acked-by: Crt Mori <[email protected]> Acked-by: Nuno Sá <[email protected]> Acked-by: Richard Genoud <[email protected]> Reviewed-by: Andy Shevchenko <[email protected]> Reviewed-by: Yury Norov (NVIDIA) <[email protected]> Signed-off-by: Yury Norov (NVIDIA) <[email protected]> [Linux commit: c1c6ab80b25c8db1e2ef5ae3ac8075d2c242ae13] Signed-off-by: Mikhail Kshevetskiy <[email protected]> Reviewed-by: David Lechner <[email protected]> Reviewed-by: Simon Glass <[email protected]>
Diffstat (limited to 'include')
-rw-r--r--include/linux/bitfield.h59
1 files changed, 59 insertions, 0 deletions
diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
index ef81901bc41..18cf57aeb2c 100644
--- a/include/linux/bitfield.h
+++ b/include/linux/bitfield.h
@@ -16,6 +16,7 @@
* FIELD_{GET,PREP} macros take as first parameter shifted mask
* from which they extract the base mask and shift amount.
* Mask must be a compilation time constant.
+ * field_{get,prep} are variants that take a non-const mask.
*
* Example:
*
@@ -223,4 +224,62 @@ __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; \
+ })
+
+/**
+ * field_prep() - prepare a bitfield element
+ * @mask: shifted mask defining the field's length and position, must be
+ * non-zero
+ * @val: value to put in the field
+ *
+ * Return: field value masked and shifted to its final destination
+ *
+ * field_prep() masks and shifts up the value. The result should be
+ * combined with other fields of the bitfield using logical OR.
+ * Unlike FIELD_PREP(), @mask is not limited to a compile-time constant.
+ * Typical usage patterns are a value stored in a table, or calculated by
+ * shifting a constant by a variable number of bits.
+ * 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))
+
+/**
+ * field_get() - extract a bitfield element
+ * @mask: shifted mask defining the field's length and position, must be
+ * non-zero
+ * @reg: value of entire bitfield
+ *
+ * Return: extracted field value
+ *
+ * field_get() extracts the field specified by @mask from the
+ * bitfield passed in as @reg by masking and shifting it down.
+ * Unlike FIELD_GET(), @mask is not limited to a compile-time constant.
+ * Typical usage patterns are a value stored in a table, or calculated by
+ * shifting a constant by a variable number of bits.
+ * 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))
+
#endif