From: Geert Uytterhoeven <[email protected]>

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]>
---
 include/linux/bitfield.h | 59 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)

diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
index 63928f17322..efad7227bdc 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:
  *
@@ -203,4 +204,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
-- 
2.53.0

Reply via email to