mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
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 withing new macros.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Acked-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Acked-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Acked-by: Crt Mori <cmo@melexis.com>
Acked-by: Nuno Sá <nuno.sa@analog.com>
Acked-by: Richard Genoud <richard.genoud@bootlin.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Reviewed-by: Yury Norov (NVIDIA) <yury.norov@gmail.com>
Signed-off-by: Yury Norov (NVIDIA) <yury.norov@gmail.com>
This commit is contained in:
committed by
Yury Norov (NVIDIA)
parent
2a6c045640
commit
c1c6ab80b2
@@ -17,6 +17,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:
|
||||
*
|
||||
@@ -240,4 +241,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
|
||||
|
||||
Reference in New Issue
Block a user