aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2023-01-18 14:26:53 +0100
committerJohannes Berg <johannes.berg@intel.com>2023-01-19 14:46:25 +0100
commite2192de59e457aef8d1f055a452131f0b3e5d097 (patch)
treea7d47bf68cbc47043c0d80d259550c0ba2d7d8ba
parent41ade47c1273ca0e61c36f2cccad37473f0b2422 (diff)
downloadiwlwifi-next-e2192de59e457aef8d1f055a452131f0b3e5d097.tar.gz
bitfield: add FIELD_PREP_CONST()
Neither FIELD_PREP() nor *_encode_bits() can be used in constant contexts (such as initializers), but we don't want to define shift constants for all masks just for use in initializers, and having checks that the values fit is also useful. Therefore, add FIELD_PREP_CONST() which is a smaller version of FIELD_PREP() that can only take constant arguments and has less friendly (but not less strict) error checks, and expands to a constant value. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Link: https://lore.kernel.org/r/20230118142652.53f20593504b.Iaeea0aee77a6493d70e573b4aa55c91c00e01e4b@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--include/linux/bitfield.h26
1 files changed, 26 insertions, 0 deletions
diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
index c9be1657f03d92..ebfa12f6950121 100644
--- a/include/linux/bitfield.h
+++ b/include/linux/bitfield.h
@@ -115,6 +115,32 @@
((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \
})
+#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
+ *
+ * FIELD_PREP_CONST() masks and shifts up the value. The result should
+ * be combined with other fields of the bitfield using logical OR.
+ *
+ * Unlike FIELD_PREP() this is a constant expression and can therefore
+ * 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 */ \
+ BUILD_BUG_ON_ZERO((_mask) == 0) + \
+ /* 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)) \
+ )
+
/**
* FIELD_GET() - extract a bitfield element
* @_mask: shifted mask defining the field's length and position