summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuo Jie <quic_luoj@quicinc.com>2025-04-17 18:47:08 +0800
committerYury Norov <yury.norov@gmail.com>2025-04-29 15:58:38 -0400
commita256ae22570ee4c3427fdc703a58a89afee6a332 (patch)
tree8168df33dba0f19402ca698901f73cb6196e38e2
parent89a44a808814d4717a8bf945ddebd5c39bfffcf4 (diff)
bitfield: Add FIELD_MODIFY() helper
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>
-rw-r--r--include/linux/bitfield.h21
1 files changed, 19 insertions, 2 deletions
diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
index 63928f173223..6d9a53db54b6 100644
--- a/include/linux/bitfield.h
+++ b/include/linux/bitfield.h
@@ -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)
@@ -156,6 +156,23 @@
(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")