]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bitfield: Add FIELD_MODIFY() helper
authorLuo Jie <quic_luoj@quicinc.com>
Thu, 17 Apr 2025 10:47:08 +0000 (18:47 +0800)
committerYury Norov <yury.norov@gmail.com>
Tue, 29 Apr 2025 19:58:38 +0000 (15:58 -0400)
Add a helper for replacing the contents of bitfield in memory
with the specified value.

Even though a helper xxx_replace_bits() is available, it is not
well documented, and only reports errors at the run time, which
will not be helpful to catch possible overflow errors due to
incorrect parameter types used.

FIELD_MODIFY(REG_FIELD_C, &reg, c) is the wrapper to the code below.

reg &= ~REG_FIELD_C;
reg |= FIELD_PREP(REG_FIELD_C, c);

Yury: trim commit message, align backslashes.

Signed-off-by: Luo Jie <quic_luoj@quicinc.com>
Signed-off-by: Yury Norov <yury.norov@gmail.com>
include/linux/bitfield.h

index 63928f1732230700c820f2ab91e946f8e8ec289b..6d9a53db54b66c0833973c880444bd289d9667b1 100644 (file)
@@ -8,6 +8,7 @@
 #define _LINUX_BITFIELD_H
 
 #include <linux/build_bug.h>
+#include <linux/typecheck.h>
 #include <asm/byteorder.h>
 
 /*
@@ -38,8 +39,7 @@
  *       FIELD_PREP(REG_FIELD_D, 0x40);
  *
  * Modify:
- *  reg &= ~REG_FIELD_C;
- *  reg |= FIELD_PREP(REG_FIELD_C, c);
+ *  FIELD_MODIFY(REG_FIELD_C, &reg, c);
  */
 
 #define __bf_shf(x) (__builtin_ffsll(x) - 1)
                (typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \
        })
 
+/**
+ * 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
+ *
+ * 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)                                              \
+       ({                                                                              \
+               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));    \
+       })
+
 extern void __compiletime_error("value doesn't fit into mask")
 __field_overflow(void);
 extern void __compiletime_error("bad bitfield mask")